feat(checkout): improve wallet top-up flow with auto deficit pre-fill on insufficient funds
All checks were successful
Deploy Canina / deploy (push) Successful in 1m33s
All checks were successful
Deploy Canina / deploy (push) Successful in 1m33s
This commit is contained in:
parent
992c815749
commit
6454c18071
@ -118,7 +118,11 @@ export default function CheckoutPage() {
|
||||
|
||||
// 2. Validate wallet balance if payment method is wallet
|
||||
if (paymentMethod === 'wallet' && (profile.walletBalance || 0) < totalAmount) {
|
||||
toast.error(`موجودی کیف پول شما (${(profile.walletBalance || 0).toLocaleString('fa-IR')} تومان) کمتر از مبلغ نهایی سفارش (${totalAmount.toLocaleString('fa-IR')} تومان) است. لطفاً ابتدا کیف پول خود را شارژ کنید.`);
|
||||
const neededAmount = totalAmount - (profile.walletBalance || 0);
|
||||
toast.error(
|
||||
`موجودی کیف پول شما (${(profile.walletBalance || 0).toLocaleString('fa-IR')} تومان) کمتر از مبلغ سفارش (${totalAmount.toLocaleString('fa-IR')} تومان) است. کادر افزایش موجودی (${neededAmount.toLocaleString('fa-IR')} تومان) باز شد.`,
|
||||
);
|
||||
setShowTopUpModal(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -560,7 +564,7 @@ export default function CheckoutPage() {
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className={cn("text-[10px] font-bold truncate", pay.id === 'wallet' ? "text-canina-blue" : "text-medical-gray-400")}>{pay.desc}</p>
|
||||
{pay.id === 'wallet' && pay.enabled && (profile.walletBalance || 0) === 0 && (
|
||||
{pay.id === 'wallet' && pay.enabled && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
@ -823,6 +827,7 @@ export default function CheckoutPage() {
|
||||
|
||||
<TopUpModal
|
||||
isOpen={showTopUpModal}
|
||||
initialAmount={Math.max(0, (getTotal() + shippingFee) - (profile.walletBalance || 0))}
|
||||
onClose={() => setShowTopUpModal(false)}
|
||||
onConfirm={(amt) => {
|
||||
useUserStore.setState(state => ({
|
||||
|
||||
@ -12,6 +12,7 @@ interface TopUpModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onConfirm?: (amount: number) => void;
|
||||
initialAmount?: number;
|
||||
}
|
||||
|
||||
const PRESET_AMOUNTS = [
|
||||
@ -20,11 +21,17 @@ const PRESET_AMOUNTS = [
|
||||
{ label: "۲,۰۰۰,۰۰۰ تومان", value: 2000000 },
|
||||
];
|
||||
|
||||
export default function TopUpModal({ isOpen, onClose }: TopUpModalProps) {
|
||||
const [amount, setAmount] = useState<string>("");
|
||||
export default function TopUpModal({ isOpen, onClose, initialAmount }: TopUpModalProps) {
|
||||
const [amount, setAmount] = useState<string>(() => (initialAmount ? String(initialAmount) : ""));
|
||||
const [selectedPreset, setSelectedPreset] = useState<number | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (initialAmount && initialAmount > 0) {
|
||||
setAmount(String(initialAmount));
|
||||
}
|
||||
}, [initialAmount, isOpen]);
|
||||
|
||||
const isCardToCardEnabled = useSettingsStore((state) =>
|
||||
state.getBoolean("payment_card_to_card_enabled", false),
|
||||
);
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
"49": "SmartAdvisorService",
|
||||
"50": "TestimonialsService",
|
||||
"51": "Role & Core Objective",
|
||||
"52": ".handleZibalCallback",
|
||||
"52": ".initiateOrderPayment",
|
||||
"53": "ZibalEBankService",
|
||||
"54": "compilerOptions",
|
||||
"55": "Media.tsx",
|
||||
@ -295,13 +295,13 @@
|
||||
"293": "typescript",
|
||||
"294": "app-audit-verification.e2e-spec.d.ts",
|
||||
"295": "app.e2e-spec.d.ts",
|
||||
"296": "wiki/page.tsx",
|
||||
"296": "dashboard/page.tsx",
|
||||
"297": "CreateHealthLogDto",
|
||||
"298": "eslint-config-prettier",
|
||||
"299": "CreateReminderDto",
|
||||
"300": ".sendOtp",
|
||||
"301": "track/page.tsx",
|
||||
"302": "eslint-config-next",
|
||||
"302": "@types/react-dom",
|
||||
"303": "eslint-plugin-prettier",
|
||||
"305": "RouteErrorBoundary",
|
||||
"309": "globals",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -295,13 +295,13 @@
|
||||
"293": "typescript",
|
||||
"294": "app-audit-verification.e2e-spec.d.ts",
|
||||
"295": "app.e2e-spec.d.ts",
|
||||
"296": "@types/react-dom",
|
||||
"296": "wiki/page.tsx",
|
||||
"297": "CreateHealthLogDto",
|
||||
"298": "eslint-config-prettier",
|
||||
"299": "CreateReminderDto",
|
||||
"300": ".sendOtp",
|
||||
"301": "track/page.tsx",
|
||||
"302": "dashboard/page.tsx",
|
||||
"302": "eslint-config-next",
|
||||
"303": "eslint-plugin-prettier",
|
||||
"305": "RouteErrorBoundary",
|
||||
"309": "globals",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Graph Report - canina (2026-08-22)
|
||||
|
||||
## Corpus Check
|
||||
- 539 files · ~762,534 words
|
||||
- 539 files · ~762,735 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
@ -10,7 +10,7 @@
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `f9e40564`
|
||||
- Built from commit: `d62787cd`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@ -294,12 +294,12 @@
|
||||
- useSettingsStore
|
||||
- @types/supertest
|
||||
- typescript
|
||||
- @types/react-dom
|
||||
- wiki/page.tsx
|
||||
- CreateHealthLogDto
|
||||
- eslint-config-prettier
|
||||
- CreateReminderDto
|
||||
- track/page.tsx
|
||||
- dashboard/page.tsx
|
||||
- eslint-config-next
|
||||
- eslint-plugin-prettier
|
||||
- RouteErrorBoundary
|
||||
- globals
|
||||
@ -659,7 +659,7 @@ Nodes (16): BlogPost, BlogPreviewSection(), ProductDetailModalProps, SafeImage()
|
||||
|
||||
### Community 81 - "devDependencies"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): eslint-config-next, devDependencies, eslint, eslint-config-next, jsdom, tailwindcss, @tailwindcss/postcss, @types/node (+7 more)
|
||||
Nodes (15): devDependencies, eslint, jsdom, tailwindcss, @tailwindcss/postcss, @types/node, @types/react-dom, @vitejs/plugin-react (+7 more)
|
||||
|
||||
### Community 82 - "auth.controller.ts"
|
||||
Cohesion: 0.18
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
# Graph Report - canina (2026-08-22)
|
||||
|
||||
## Corpus Check
|
||||
- 539 files · ~762,735 words
|
||||
- 539 files · ~762,770 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
@ -10,7 +10,7 @@
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `d62787cd`
|
||||
- Built from commit: `992c8157`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
- SmartAdvisorService
|
||||
- TestimonialsService
|
||||
- Role & Core Objective
|
||||
- .handleZibalCallback
|
||||
- .initiateOrderPayment
|
||||
- ZibalEBankService
|
||||
- compilerOptions
|
||||
- Media.tsx
|
||||
@ -294,12 +294,12 @@
|
||||
- useSettingsStore
|
||||
- @types/supertest
|
||||
- typescript
|
||||
- wiki/page.tsx
|
||||
- dashboard/page.tsx
|
||||
- CreateHealthLogDto
|
||||
- eslint-config-prettier
|
||||
- CreateReminderDto
|
||||
- track/page.tsx
|
||||
- eslint-config-next
|
||||
- @types/react-dom
|
||||
- eslint-plugin-prettier
|
||||
- RouteErrorBoundary
|
||||
- globals
|
||||
@ -374,8 +374,8 @@ Cohesion: 0.11
|
||||
Nodes (18): FeaturedProducts(), ProductCard(), OrderSuccess(), PrescriptionUploadModal(), PrescriptionUploadModalProps, SearchResultsPage(), OrderRowSkeleton(), PetProfileSkeleton() (+10 more)
|
||||
|
||||
### Community 9 - "Roles"
|
||||
Cohesion: 0.20
|
||||
Nodes (15): Roles(), PaymentController, ApiBadRequestResponse, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags, Body (+7 more)
|
||||
Cohesion: 0.24
|
||||
Nodes (13): Roles(), PaymentController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get (+5 more)
|
||||
|
||||
### Community 10 - "DoctorQueryDto"
|
||||
Cohesion: 0.08
|
||||
@ -467,7 +467,7 @@ Nodes (7): JwtAuthGuard, Injectable, ROLES_KEY, RequestWithUser, RolesGuard, Inj
|
||||
|
||||
### Community 32 - "ZibalService"
|
||||
Cohesion: 0.09
|
||||
Nodes (5): Put, PaymentService, Injectable, Injectable, ZibalService
|
||||
Nodes (4): PaymentService, Injectable, Injectable, ZibalService
|
||||
|
||||
### Community 33 - "راهنمای تست سیستم (Software Testing)"
|
||||
Cohesion: 0.07
|
||||
@ -545,9 +545,9 @@ Nodes (14): TestimonialsController, ApiBearerAuth, ApiOperation, ApiTags, Body,
|
||||
Cohesion: 0.09
|
||||
Nodes (22): CREATE MODE — Normal Operation, Expected JSON Output Schema, File Scope Boundary, Forbidden Actions, MODE 1: REVIEW (called during Review Phase), MODE 2: CONTENT CREATION (standalone task from backlog), Operating Modes, Operational Rules & Boundaries (+14 more)
|
||||
|
||||
### Community 52 - ".handleZibalCallback"
|
||||
Cohesion: 0.25
|
||||
Nodes (7): ApiPropertyOptional, IsOptional, IsString, ZibalCallbackQueryDto, Res, Headers, Ip
|
||||
### Community 52 - ".initiateOrderPayment"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): ApiPropertyOptional, IsOptional, IsString, ZibalCallbackQueryDto, ApiBadRequestResponse, ApiOkResponse, Req, Res (+2 more)
|
||||
|
||||
### Community 54 - "compilerOptions"
|
||||
Cohesion: 0.06
|
||||
@ -586,7 +586,7 @@ Cohesion: 0.14
|
||||
Nodes (16): BlogsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+8 more)
|
||||
|
||||
### Community 63 - "ApiOperation"
|
||||
Cohesion: 0.17
|
||||
Cohesion: 0.19
|
||||
Nodes (8): ApiOperation, ApiQuery, Get, Query, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
|
||||
### Community 64 - "BannersService"
|
||||
@ -659,7 +659,7 @@ Nodes (16): BlogPost, BlogPreviewSection(), ProductDetailModalProps, SafeImage()
|
||||
|
||||
### Community 81 - "devDependencies"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): devDependencies, eslint, jsdom, tailwindcss, @tailwindcss/postcss, @types/node, @types/react-dom, @vitejs/plugin-react (+7 more)
|
||||
Nodes (15): eslint-config-next, devDependencies, eslint, eslint-config-next, jsdom, tailwindcss, @tailwindcss/postcss, @types/node (+7 more)
|
||||
|
||||
### Community 82 - "auth.controller.ts"
|
||||
Cohesion: 0.18
|
||||
@ -726,8 +726,8 @@ Cohesion: 0.15
|
||||
Nodes (13): jest, collectCoverageFrom, coverageDirectory, moduleFileExtensions, rootDir, testEnvironment, testRegex, transform (+5 more)
|
||||
|
||||
### Community 98 - "AdminService"
|
||||
Cohesion: 0.13
|
||||
Nodes (5): Delete, Param, Put, AdminService, Injectable
|
||||
Cohesion: 0.18
|
||||
Nodes (4): Delete, Param, AdminService, Injectable
|
||||
|
||||
### Community 99 - "Comprehensive Change Log"
|
||||
Cohesion: 0.15
|
||||
@ -1042,8 +1042,8 @@ Cohesion: 0.29
|
||||
Nodes (6): AdminLoginDto, ApiProperty, IsEmail, IsNotEmpty, IsString, MinLength
|
||||
|
||||
### Community 215 - "AdminController"
|
||||
Cohesion: 0.25
|
||||
Nodes (5): AdminController, ApiBearerAuth, ApiTags, Controller, UseGuards
|
||||
Cohesion: 0.14
|
||||
Nodes (6): AdminController, ApiBearerAuth, ApiTags, Controller, Put, UseGuards
|
||||
|
||||
### Community 220 - "getPageMetadata"
|
||||
Cohesion: 0.13
|
||||
@ -1107,7 +1107,7 @@ _Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `ApiResponse` connect `ApiResponse` to `OrdersService`, `UsersService`, `PetsController`, `ProductsService`, `src/services/api.ts`, `AuthController`?**
|
||||
_High betweenness centrality (0.064) - this node is a cross-community bridge._
|
||||
- **Why does `Roles()` connect `Roles` to `BannersService`, `ZibalService`, `CmsController`, `B2BService`, `reviews.controller.ts`, `tickets.controller.ts`, `SslController`, `IngredientsService`, `FaqService`, `MenuService`, `ContactService`, `ProductsService`, `PrescriptionsService`, `SmartAdvisorService`, `TestimonialsService`, `SmsService`, `WholesaleService`, `JwtAuthGuard`?**
|
||||
- **Why does `Roles()` connect `Roles` to `BannersService`, `CmsController`, `B2BService`, `reviews.controller.ts`, `tickets.controller.ts`, `SslController`, `IngredientsService`, `FaqService`, `MenuService`, `ContactService`, `ProductsService`, `PrescriptionsService`, `SmartAdvisorService`, `TestimonialsService`, `SmsService`, `WholesaleService`, `JwtAuthGuard`?**
|
||||
_High betweenness centrality (0.060) - this node is a cross-community bridge._
|
||||
- **Why does `PrismaService` connect `PrismaService` to `OrdersService`, `CmsController`, `app.module.ts`, `reviews.controller.ts`, `tickets.controller.ts`, `DoctorQueryDto`, `MenuService`, `pets/pets.controller.ts`, `auth.service.ts`, `ProductsService`, `CreateVideoDto`, `SmsService`, `WholesaleService`, `ZibalService`, `CategoriesController`, `B2BService`, `UsersService`, `IngredientsService`, `FaqService`, `MediaController`, `MetricsController`, `ContactService`, `zibal.service.ts`, `PrescriptionsService`, `SmartAdvisorService`, `TestimonialsService`, `ZibalEBankService`, `admin.module.ts`, `PetsController`, `PaginationDto`, `BannersService`, `admin.service.ts`, `seo.module.ts`, `AuthController`, `ApiResponse`, `payment.service.ts`, `PetsService`, `WholesaleApplyDto`?**
|
||||
_High betweenness centrality (0.040) - this node is a cross-community bridge._
|
||||
|
||||
2
graphify-out/cache/stat-index.json
vendored
2
graphify-out/cache/stat-index.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user