From feb5727c0ebd20bf26ff98458ea87f1d87a55a8f Mon Sep 17 00:00:00 2001 From: saeed Date: Wed, 28 Oct 2026 14:29:12 +0330 Subject: [PATCH] feat: order revision, rial wage from variant, product tags; drop user-app-v2 Admin order edit with category chips and timeline; customer checkout charges variant rialWage; product tags; retire the unused user-app-v2 tree. Co-authored-by: Cursor --- .env.example | 1 - DELIVERY.md | 8 +- DOCKER.md | 4 +- .../public}/img/no-items.png | Bin apps/admin-panel/src/api/endpoints.ts | 1 + apps/admin-panel/src/utils/orderStatus.ts | 75 + .../src/views/apps/product/AddProduct.vue | 29 +- .../src/views/apps/product/ProductList.vue | 23 + .../views/apps/product/productListModel.ts | 1 + .../src/views/customer/omde/omdeListModel.ts | 2 +- .../customer/reagentList/ReagentListModel.ts | 2 +- apps/admin-panel/src/views/order/List.vue | 279 +- apps/admin-panel/src/views/order/OmdeList.vue | 251 +- .../src/views/order/OrderDetailBody.vue | 1013 +++ .../src/views/order/OrderStatusTimeline.vue | 396 ++ .../admin-panel/src/views/order/TaminList.vue | 93 +- apps/admin-panel/vite.config.ts | 7 +- .../20261028120000_product_tags/migration.sql | 2 + .../migration.sql | 29 + apps/api/prisma/schema.prisma | 46 + apps/api/scripts/smoke-apps.cjs | 32 +- .../admin-orders/admin-orders.controller.ts | 45 + .../admin-orders/admin-orders.service.ts | 100 +- .../admin-products.controller.ts | 6 + .../admin-products/admin-products.service.ts | 29 +- .../modules/catalog/catalog-paging.spec.ts | 17 +- .../src/modules/catalog/catalog.service.ts | 13 +- .../customer-auth/customer-auth.controller.ts | 56 +- .../customer-auth/customer-auth.module.ts | 3 +- .../modules/customers/customers.service.ts | 98 +- .../customers/order-items-include.spec.ts | 6 +- apps/api/src/modules/iam/iam.service.ts | 2 +- .../modules/orders/order-revision.service.ts | 356 + apps/api/src/modules/orders/orders.module.ts | 5 +- .../src/modules/orders/orders.service.spec.ts | 24 +- apps/api/src/modules/orders/orders.service.ts | 21 +- apps/api/src/modules/pricing/wage-formula.ts | 3 +- apps/user-app-v2/.dockerignore | 5 - apps/user-app-v2/Dockerfile | 8 - .../dist/assets/AppPullRefresh-DK9DbvVA.js | 1 - .../dist/assets/AppPullRefresh-DmpEfa19.css | 1 - .../dist/assets/AppearanceView-Hcg5Pdvo.js | 1 - .../dist/assets/AppearanceView-X-VnjBQ6.css | 1 - .../dist/assets/CartView-CKLnMvnA.js | 1 - .../dist/assets/CartView-CyRqcM3j.css | 1 - .../dist/assets/ChildOrdersView-D6xgBGGQ.css | 1 - .../dist/assets/ChildOrdersView-DGVuNcOL.js | 1 - .../dist/assets/CollectionView-Bfngyqms.css | 1 - .../dist/assets/CollectionView-CXUuUCmE.js | 1 - .../assets/CompleteProfileView-hH_R3jUX.css | 1 - .../assets/CompleteProfileView-j0AONcFj.js | 1 - .../assets/CustomerChoiceView-DB7yiqRu.css | 1 - .../assets/CustomerChoiceView-zmQgjVme.js | 1 - .../dist/assets/DashboardView-BTOUUwpE.js | 1 - .../dist/assets/DashboardView-BnSrdKUp.css | 1 - .../dist/assets/FavoritesView-BNvXFK2Z.css | 1 - .../dist/assets/FavoritesView-BS-C2uMv.js | 1 - .../dist/assets/FormItemContext-0CnJhEk0.js | 1 - .../dist/assets/HomeView-DSTuecmb.css | 1 - .../dist/assets/HomeView-DgtGcpTB.js | 1 - .../assets/IRANSansWeb_FaNum-BLA2CtIC.woff2 | Bin 27944 -> 0 bytes .../assets/IRANSansWeb_FaNum-C2LCNwav.woff | Bin 35161 -> 0 bytes .../IRANSansWeb_FaNum_Black-BFAfOkt4.woff2 | Bin 25776 -> 0 bytes .../IRANSansWeb_FaNum_Black-BZZZWzNZ.woff | Bin 33025 -> 0 bytes .../IRANSansWeb_FaNum_Bold-C8urhp07.woff2 | Bin 27316 -> 0 bytes .../IRANSansWeb_FaNum_Bold-DFiUzN7v.woff | Bin 34689 -> 0 bytes .../IRANSansWeb_FaNum_Light-B637MNLG.woff2 | Bin 28400 -> 0 bytes .../IRANSansWeb_FaNum_Light-Blhumvhg.woff | Bin 35709 -> 0 bytes .../IRANSansWeb_FaNum_Medium-C2CKjrKB.woff2 | Bin 25784 -> 0 bytes .../IRANSansWeb_FaNum_Medium-DJxlPmBM.woff | Bin 32485 -> 0 bytes ...IRANSansWeb_FaNum_UltraLight-X2tWVnbe.woff | Bin 35537 -> 0 bytes ...RANSansWeb_FaNum_UltraLight-hW-WDKY9.woff2 | Bin 28208 -> 0 bytes .../dist/assets/IamCallback-CstyCPgT.js | 1 - .../dist/assets/KeyCode-C7e-XTEK.js | 1 - .../dist/assets/LoginRegisterView-Cc9V9cq7.js | 1 - .../assets/LoginRegisterView-DIgrvcKn.css | 1 - .../dist/assets/NewestView-CRqVtDuM.css | 1 - .../dist/assets/NewestView-foURH8az.js | 1 - .../dist/assets/NotificationsView-AysksH6v.js | 1 - .../assets/NotificationsView-BYJ2kMU3.css | 1 - .../dist/assets/OrdersView-D-jf8PUm.js | 1 - .../dist/assets/OrdersView-DNKGvr4J.css | 1 - .../dist/assets/PageBar-BBMNYL0j.js | 1 - .../dist/assets/PageBar-DJWT4eaj.css | 1 - .../dist/assets/ProductCard-C0a9p2bL.js | 1 - .../dist/assets/ProductCard-D6-KxSf7.css | 1 - .../dist/assets/ProfileView-CRrMEcnO.css | 1 - .../dist/assets/ProfileView-jxoFJaTe.js | 1 - .../dist/assets/RateStrip-B00WoPCp.css | 1 - .../dist/assets/RateStrip-yK7NvWwz.js | 1 - .../dist/assets/ReportView-BrhJZMTH.css | 1 - .../dist/assets/ReportView-DRQCm5Pz.js | 1 - .../dist/assets/SearchInput-BYt0pCew.js | 1 - .../dist/assets/SearchInput-DEfgrsbu.css | 1 - .../dist/assets/SearchView-B8CO_3LB.css | 1 - .../dist/assets/SearchView-BIw5FNh3.js | 1 - .../dist/assets/SectionHead-CDGrZss6.css | 1 - .../dist/assets/SectionHead-LafpWeqY.js | 1 - .../dist/assets/TransactionsView-BfQHBrDd.js | 1 - .../dist/assets/TransactionsView-QJUT0Agr.css | 1 - .../dist/assets/brand-logo-c8-B3-lR.png | Bin 89320 -> 0 bytes .../dist/assets/catalogStore-CR1VkPNU.js | 1 - .../dist/assets/classCallCheck-BwcnXnXD.js | 1 - .../dist/assets/favoritEmpty-kbtPAdi5.svg | 108 - .../dist/assets/filters-qWhZyCzD.js | 5 - .../user-app-v2/dist/assets/index-BEKTkTDh.js | 25 - .../user-app-v2/dist/assets/index-BMHplzPz.js | 1 - .../dist/assets/index-C3cFbOta.css | 1 - .../user-app-v2/dist/assets/index-D8i4h-PU.js | 6264 ----------------- apps/user-app-v2/dist/assets/raf-nDFcuFT6.js | 1 - .../assets/shipping-and-delivery-CyUGL93q.png | Bin 20935 -> 0 bytes .../sports-and-competition-ao926_SX.png | Bin 21591 -> 0 bytes .../dist/assets/usePagedProducts-Bcf85uEP.js | 1 - .../workbox-window.prod.es5-BqEJf4Xk.js | 2 - .../assets/yekan_bakh_fanum_bold-B1U8HUd_.eot | Bin 60024 -> 0 bytes .../assets/yekan_bakh_fanum_bold-BgJhv14C.ttf | Bin 60024 -> 0 bytes .../yekan_bakh_fanum_bold-DiCmzWh_.woff | Bin 60024 -> 0 bytes .../assets/yekan_bakh_fanum_fat-ByLTFLyk.eot | Bin 60300 -> 0 bytes .../assets/yekan_bakh_fanum_fat-D7l80IzQ.ttf | Bin 60300 -> 0 bytes .../yekan_bakh_fanum_heavy-DcWv4PAq.woff | Bin 60096 -> 0 bytes .../yekan_bakh_fanum_heavy-DcdOma-5.ttf | Bin 60096 -> 0 bytes .../yekan_bakh_fanum_heavy-h9lE53XZ.eot | Bin 60096 -> 0 bytes .../yekan_bakh_fanum_light-BVC5pEtm.ttf | Bin 60996 -> 0 bytes .../yekan_bakh_fanum_light-DBLK7lys.eot | Bin 60996 -> 0 bytes .../yekan_bakh_fanum_light-MBz7xfzX.woff | Bin 60996 -> 0 bytes .../yekan_bakh_fanum_medium-C7lE-mP3.woff | Bin 60364 -> 0 bytes .../yekan_bakh_fanum_medium-K0xA3c9N.eot | Bin 60364 -> 0 bytes .../yekan_bakh_fanum_medium-udXv5Dbe.ttf | Bin 60364 -> 0 bytes .../yekan_bakh_fanum_regular-5O8oud7N.ttf | Bin 60576 -> 0 bytes .../yekan_bakh_fanum_regular-D-3AgpAQ.eot | Bin 60576 -> 0 bytes .../yekan_bakh_fanum_regular-DYu11jPk.woff | Bin 60576 -> 0 bytes .../yekan_bakh_fanum_thin-BUP5N_wR.woff | Bin 61088 -> 0 bytes .../assets/yekan_bakh_fanum_thin-DdtkSAK0.eot | Bin 61088 -> 0 bytes .../assets/yekan_bakh_fanum_thin-wM_3S6d2.ttf | Bin 61088 -> 0 bytes apps/user-app-v2/dist/bale.png | Bin 46944 -> 0 bytes apps/user-app-v2/dist/favicon.ico | Bin 14510 -> 0 bytes apps/user-app-v2/dist/icon-192.png | Bin 13749 -> 0 bytes apps/user-app-v2/dist/icon-512.png | Bin 75164 -> 0 bytes apps/user-app-v2/dist/img/brand-logo.png | Bin 89320 -> 0 bytes apps/user-app-v2/dist/img/brand-logo.webp | Bin 17294 -> 0 bytes .../dist/img/products/bracelets-0.svg | 6 - .../dist/img/products/bracelets-1.svg | 6 - .../dist/img/products/bracelets-2.svg | 6 - .../dist/img/products/bracelets-3.svg | 6 - .../dist/img/products/bracelets-4.svg | 6 - .../dist/img/products/bracelets-5.svg | 6 - .../user-app-v2/dist/img/products/coins-0.svg | 6 - .../user-app-v2/dist/img/products/coins-1.svg | 6 - .../user-app-v2/dist/img/products/coins-2.svg | 6 - .../user-app-v2/dist/img/products/coins-3.svg | 6 - .../user-app-v2/dist/img/products/coins-4.svg | 6 - .../user-app-v2/dist/img/products/coins-5.svg | 6 - .../dist/img/products/earrings-0.svg | 6 - .../dist/img/products/earrings-1.svg | 6 - .../dist/img/products/earrings-2.svg | 6 - .../dist/img/products/earrings-3.svg | 6 - .../dist/img/products/earrings-4.svg | 6 - .../dist/img/products/earrings-5.svg | 6 - .../dist/img/products/necklaces-0.svg | 6 - .../dist/img/products/necklaces-1.svg | 6 - .../dist/img/products/necklaces-2.svg | 6 - .../dist/img/products/necklaces-3.svg | 6 - .../dist/img/products/necklaces-4.svg | 6 - .../dist/img/products/necklaces-5.svg | 6 - .../user-app-v2/dist/img/products/rings-0.svg | 6 - .../user-app-v2/dist/img/products/rings-1.svg | 6 - .../user-app-v2/dist/img/products/rings-2.svg | 6 - .../user-app-v2/dist/img/products/rings-3.svg | 6 - .../user-app-v2/dist/img/products/rings-4.svg | 6 - .../user-app-v2/dist/img/products/rings-5.svg | 6 - apps/user-app-v2/dist/index.html | 42 - apps/user-app-v2/dist/manifest.json | 3 - apps/user-app-v2/dist/manifest.webmanifest | 1 - apps/user-app-v2/dist/sw.js | 2 - apps/user-app-v2/dist/version.json | 104 - apps/user-app-v2/dist/whatsapp.png | Bin 196709 -> 0 bytes apps/user-app-v2/index.html | 41 - apps/user-app-v2/nginx.conf | 77 - apps/user-app-v2/package.json | 36 - apps/user-app-v2/postcss.config.js | 7 - apps/user-app-v2/public/bale.png | Bin 46944 -> 0 bytes apps/user-app-v2/public/favicon.ico | Bin 14510 -> 0 bytes apps/user-app-v2/public/icon-192.png | Bin 13749 -> 0 bytes apps/user-app-v2/public/icon-512.png | Bin 75164 -> 0 bytes apps/user-app-v2/public/img/brand-logo.png | Bin 89320 -> 0 bytes apps/user-app-v2/public/img/brand-logo.webp | Bin 17294 -> 0 bytes apps/user-app-v2/public/img/no-items.png | Bin 54377 -> 0 bytes .../public/img/products/bracelets-0.svg | 6 - .../public/img/products/bracelets-1.svg | 6 - .../public/img/products/bracelets-2.svg | 6 - .../public/img/products/bracelets-3.svg | 6 - .../public/img/products/bracelets-4.svg | 6 - .../public/img/products/bracelets-5.svg | 6 - .../public/img/products/coins-0.svg | 6 - .../public/img/products/coins-1.svg | 6 - .../public/img/products/coins-2.svg | 6 - .../public/img/products/coins-3.svg | 6 - .../public/img/products/coins-4.svg | 6 - .../public/img/products/coins-5.svg | 6 - .../public/img/products/earrings-0.svg | 6 - .../public/img/products/earrings-1.svg | 6 - .../public/img/products/earrings-2.svg | 6 - .../public/img/products/earrings-3.svg | 6 - .../public/img/products/earrings-4.svg | 6 - .../public/img/products/earrings-5.svg | 6 - .../public/img/products/necklaces-0.svg | 6 - .../public/img/products/necklaces-1.svg | 6 - .../public/img/products/necklaces-2.svg | 6 - .../public/img/products/necklaces-3.svg | 6 - .../public/img/products/necklaces-4.svg | 6 - .../public/img/products/necklaces-5.svg | 6 - .../public/img/products/rings-0.svg | 6 - .../public/img/products/rings-1.svg | 6 - .../public/img/products/rings-2.svg | 6 - .../public/img/products/rings-3.svg | 6 - .../public/img/products/rings-4.svg | 6 - .../public/img/products/rings-5.svg | 6 - apps/user-app-v2/public/manifest.json | 3 - apps/user-app-v2/public/whatsapp.png | Bin 196709 -> 0 bytes apps/user-app-v2/src/App.vue | 105 - apps/user-app-v2/src/api/cachedReads.ts | 21 - apps/user-app-v2/src/api/client.ts | 659 -- apps/user-app-v2/src/assets/img/1020.jpg | Bin 260948 -> 0 bytes apps/user-app-v2/src/assets/img/Vector.svg | 3 - .../user-app-v2/src/assets/img/brand-logo.png | Bin 89320 -> 0 bytes .../src/assets/img/empty/cartEmpty.svg | 47 - .../src/assets/img/empty/customerEmpty.svg | 447 -- .../src/assets/img/empty/dialogEmpty1.svg | 447 -- .../src/assets/img/empty/dialogEmpty2.svg | 69 - .../src/assets/img/empty/dialogEmpty3.svg | 127 - .../src/assets/img/empty/dialogEmpty4.svg | 128 - .../src/assets/img/empty/dialogEmpty5.svg | 36 - .../src/assets/img/empty/emp_after_search.svg | 37 - .../src/assets/img/empty/emp_basket.svg | 87 - .../assets/img/empty/emp_before_search.svg | 53 - .../src/assets/img/empty/emp_favorite.svg | 20 - .../src/assets/img/empty/emp_notification.svg | 37 - .../src/assets/img/empty/emp_search.svg | 66 - .../src/assets/img/empty/favoritEmpty.svg | 108 - .../src/assets/img/empty/gozareshEmpty.svg | 121 - .../src/assets/img/empty/ordersEmpty.svg | 90 - .../src/assets/img/empty/transactionEmpty.svg | 85 - apps/user-app-v2/src/assets/img/no-items.png | Bin 54377 -> 0 bytes .../user-app-v2/src/assets/img/order-open.png | Bin 62807 -> 0 bytes apps/user-app-v2/src/assets/img/pattern.svg | 82 - apps/user-app-v2/src/assets/img/pattern2.svg | 298 - apps/user-app-v2/src/assets/img/pattern3.svg | 10 - .../src/assets/img/registerDelay.svg | 80 - .../src/assets/img/shipping-and-delivery.png | Bin 20935 -> 0 bytes .../src/assets/img/sports-and-competition.png | Bin 21591 -> 0 bytes apps/user-app-v2/src/assets/styles/fonts.less | 120 - .../fonts/iransans/IRANSansWeb_FaNum.woff | Bin 35161 -> 0 bytes .../fonts/iransans/IRANSansWeb_FaNum.woff2 | Bin 27944 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Black.woff | Bin 33025 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Black.woff2 | Bin 25776 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Bold.woff | Bin 34689 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Bold.woff2 | Bin 27316 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Light.woff | Bin 35709 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Light.woff2 | Bin 28400 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Medium.woff | Bin 32485 -> 0 bytes .../iransans/IRANSansWeb_FaNum_Medium.woff2 | Bin 25784 -> 0 bytes .../IRANSansWeb_FaNum_UltraLight.woff | Bin 35537 -> 0 bytes .../IRANSansWeb_FaNum_UltraLight.woff2 | Bin 28208 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_bold.eot | Bin 60024 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_bold.ttf | Bin 60024 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_bold.woff | Bin 60024 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_fat.eot | Bin 60300 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_fat.ttf | Bin 60300 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_fat.woff | Bin 60300 -> 0 bytes .../fonts/yekan_bakh_fanum_hairline.eot | Bin 61132 -> 0 bytes .../fonts/yekan_bakh_fanum_hairline.ttf | Bin 61132 -> 0 bytes .../fonts/yekan_bakh_fanum_hairline.woff | Bin 61132 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_heavy.eot | Bin 60096 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_heavy.ttf | Bin 60096 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_heavy.woff | Bin 60096 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_light.eot | Bin 60996 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_light.ttf | Bin 60996 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_light.woff | Bin 60996 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_medium.eot | Bin 60364 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_medium.ttf | Bin 60364 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_medium.woff | Bin 60364 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_regular.eot | Bin 60576 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_regular.ttf | Bin 60576 -> 0 bytes .../fonts/yekan_bakh_fanum_regular.woff | Bin 60576 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_thin.eot | Bin 61088 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_thin.ttf | Bin 61088 -> 0 bytes .../styles/fonts/yekan_bakh_fanum_thin.woff | Bin 61088 -> 0 bytes apps/user-app-v2/src/assets/styles/style.less | 779 -- .../src/assets/styles/tailwind.css | 3 - apps/user-app-v2/src/brand.ts | 2 - .../src/components/AppUpdateGate.vue | 117 - .../user-app-v2/src/components/EmptyState.vue | 32 - apps/user-app-v2/src/components/Spinner.vue | 118 - .../src/components/expert/ActingAsBar.vue | 115 - .../src/components/home/CategoryGrid.vue | 103 - .../src/components/home/HeroCarousel.vue | 273 - .../src/components/home/ProductCarousel.vue | 298 - .../src/components/home/ProductPanel.vue | 125 - .../src/components/home/RateStrip.vue | 167 - .../src/components/home/SectionHead.vue | 59 - apps/user-app-v2/src/components/icon/Icon.vue | 54 - .../src/components/icon/icons.json | 1027 --- .../src/components/input/OtpInput.vue | 138 - .../src/components/input/SingleOtpInput.vue | 119 - .../src/components/product/CartItem.vue | 262 - .../src/components/product/GallerySlider.vue | 287 - .../src/components/product/OrderCard.vue | 164 - .../src/components/product/OrderItemCard.vue | 237 - .../src/components/product/ProductCard.vue | 240 - .../src/components/product/ProductMorph.vue | 541 -- .../src/components/product/SingleProduct.vue | 1352 ---- .../src/components/search/Filters.vue | 600 -- .../src/components/search/SearchInput.vue | 108 - .../src/components/ui/AppPullRefresh.vue | 82 - .../src/components/ui/Container.vue | 13 - .../src/components/ui/DropDown.vue | 162 - .../src/components/ui/IslandSheet.vue | 384 - .../src/components/ui/Navigation.vue | 187 - .../user-app-v2/src/components/ui/PageBar.vue | 160 - .../src/components/ui/RefreshOverlay.vue | 134 - .../src/components/ui/ScrollFetchSearch.vue | 50 - .../src/components/ui/SheetArt.vue | 330 - .../src/components/ui/ToastCard.vue | 325 - .../src/components/ui/ToastHost.vue | 89 - .../src/components/ui/ToggleSwitch.vue | 63 - .../components/upload/SingleImageUploader.vue | 178 - .../src/composables/useAppUpdate.ts | 84 - .../src/composables/useOrderItemProduct.ts | 37 - .../src/composables/usePagedProducts.ts | 65 - .../user-app-v2/src/composables/useProduct.ts | 90 - .../src/composables/useProductDetail.ts | 69 - .../src/composables/useProductMorph.ts | 43 - .../src/composables/useProducts.ts | 55 - apps/user-app-v2/src/composables/useToast.ts | 72 - apps/user-app-v2/src/env.d.ts | 9 - .../user-app-v2/src/layout/FullPageLayout.vue | 9 - apps/user-app-v2/src/layout/MasterLayout.vue | 90 - apps/user-app-v2/src/main.ts | 59 - apps/user-app-v2/src/router/index.ts | 213 - .../user-app-v2/src/stores/appearanceStore.ts | 120 - apps/user-app-v2/src/stores/cartStore.ts | 153 - apps/user-app-v2/src/stores/catalogStore.ts | 50 - apps/user-app-v2/src/stores/configStore.ts | 94 - apps/user-app-v2/src/stores/favoritesStore.ts | 60 - apps/user-app-v2/src/stores/filtersStore.ts | 45 - apps/user-app-v2/src/stores/navStore.ts | 85 - apps/user-app-v2/src/stores/queryCache.ts | 123 - apps/user-app-v2/src/stores/session.ts | 136 - .../user-app-v2/src/stores/transitionStore.ts | 27 - apps/user-app-v2/src/stores/wageQuoteStore.ts | 83 - .../user-app-v2/src/stores/windowDataStore.ts | 22 - apps/user-app-v2/src/sw.ts | 14 - .../src/types/moment-jalaali-shim.d.ts | 5 - apps/user-app-v2/src/types/swiper-shim.d.ts | 16 - apps/user-app-v2/src/utils/checkAccess.ts | 6 - apps/user-app-v2/src/utils/filters.ts | 38 - apps/user-app-v2/src/utils/orderStatus.ts | 96 - apps/user-app-v2/src/utils/validator.ts | 9 - apps/user-app-v2/src/views/CartView.vue | 494 -- apps/user-app-v2/src/views/HomeView.vue | 368 - apps/user-app-v2/src/views/NewestView.vue | 97 - .../src/views/expert/ChildOrdersView.vue | 431 -- .../src/views/expert/CustomerChoiceView.vue | 421 -- .../src/views/report/ReportDocument.vue | 198 - .../src/views/report/ReportView.vue | 444 -- .../src/views/search/CollectionView.vue | 121 - .../src/views/search/SearchView.vue | 329 - .../src/views/user/AppearanceView.vue | 341 - .../src/views/user/CompleteProfileView.vue | 190 - .../src/views/user/DashboardView.vue | 775 -- .../src/views/user/FavoritesView.vue | 131 - .../src/views/user/IamCallback.vue | 45 - .../src/views/user/LoginRegisterView.vue | 14 - apps/user-app-v2/src/views/user/LoginView.vue | 377 - .../src/views/user/NotificationsView.vue | 51 - .../user-app-v2/src/views/user/OrdersView.vue | 901 --- .../src/views/user/ProfileView.vue | 329 - .../src/views/user/RegisterView.vue | 757 -- .../src/views/user/TransactionsView.vue | 357 - apps/user-app-v2/tailwind.config.js | 16 - apps/user-app-v2/themeConfig/appearance.ts | 155 - apps/user-app-v2/themeConfig/colors.dark.json | 32 - apps/user-app-v2/themeConfig/colors.json | 39 - apps/user-app-v2/themeConfig/themeConfig.ts | 53 - apps/user-app-v2/tsconfig.json | 14 - apps/user-app-v2/vite.config.ts | 74 - apps/user-app/index.html | 19 +- apps/user-app/src/App.vue | 17 + apps/user-app/src/api/client.ts | 58 + apps/user-app/src/assets/styles/style.less | 28 + .../src/components/expert/ActingAsBar.vue | 4 +- .../src/components/product/CartItem.vue | 19 +- .../src/components/product/OrderCard.vue | 23 +- .../src/components/product/OrderItemCard.vue | 171 +- .../src/components/product/ProductCard.vue | 25 + .../src/components/product/ProductMorph.vue | 9 +- .../src/components/product/ProductRow.vue | 24 + .../src/components/product/SingleProduct.vue | 129 +- .../src/components/ui/AppPullRefresh.vue | 6 +- apps/user-app/src/components/ui/Container.vue | 15 +- .../user-app/src/components/ui/Navigation.vue | 6 +- apps/user-app/src/components/ui/PageBar.vue | 5 +- .../src/components/ui/ScrollFetchSearch.vue | 10 +- apps/user-app/src/components/ui/ToastHost.vue | 5 +- .../src/composables/useOrderItemProduct.ts | 3 +- apps/user-app/src/layout/MasterLayout.vue | 2 +- apps/user-app/src/main.ts | 2 + apps/user-app/src/router/index.ts | 7 +- apps/user-app/src/stores/cartStore.ts | 8 + .../user-app/src/stores/notificationsStore.ts | 72 + apps/user-app/src/utils/filters.ts | 4 +- apps/user-app/src/utils/notificationCopy.ts | 33 + apps/user-app/src/views/CartView.vue | 55 +- apps/user-app/src/views/HomeView.vue | 35 +- .../user-app/src/views/user/DashboardView.vue | 5 +- .../src/views/user/NotificationsView.vue | 420 +- apps/user-app/themeConfig/appearance.ts | 2 +- apps/user-app/tsconfig.tsbuildinfo | 2 +- apps/user-app/vite.config.ts | 7 +- brand.ts | 4 +- docker-compose.yml | 11 - docs/BRANDING.md | 4 +- docs/REPLICATION-CHECKLIST.md | 2 +- docs/RIAL-WAGE-PORT.md | 193 + docs/parity/PROTECTED.md | 3 + package.json | 2 +- pnpm-lock.yaml | 70 - scripts/app-version.d.mts | 2 +- scripts/app-version.mjs | 6 +- 429 files changed, 3942 insertions(+), 30302 deletions(-) rename apps/{user-app-v2/dist => admin-panel/public}/img/no-items.png (100%) create mode 100644 apps/admin-panel/src/utils/orderStatus.ts create mode 100644 apps/admin-panel/src/views/order/OrderDetailBody.vue create mode 100644 apps/admin-panel/src/views/order/OrderStatusTimeline.vue create mode 100644 apps/api/prisma/migrations/20261028120000_product_tags/migration.sql create mode 100644 apps/api/prisma/migrations/20261028140000_order_revision/migration.sql create mode 100644 apps/api/src/modules/orders/order-revision.service.ts delete mode 100644 apps/user-app-v2/.dockerignore delete mode 100644 apps/user-app-v2/Dockerfile delete mode 100644 apps/user-app-v2/dist/assets/AppPullRefresh-DK9DbvVA.js delete mode 100644 apps/user-app-v2/dist/assets/AppPullRefresh-DmpEfa19.css delete mode 100644 apps/user-app-v2/dist/assets/AppearanceView-Hcg5Pdvo.js delete mode 100644 apps/user-app-v2/dist/assets/AppearanceView-X-VnjBQ6.css delete mode 100644 apps/user-app-v2/dist/assets/CartView-CKLnMvnA.js delete mode 100644 apps/user-app-v2/dist/assets/CartView-CyRqcM3j.css delete mode 100644 apps/user-app-v2/dist/assets/ChildOrdersView-D6xgBGGQ.css delete mode 100644 apps/user-app-v2/dist/assets/ChildOrdersView-DGVuNcOL.js delete mode 100644 apps/user-app-v2/dist/assets/CollectionView-Bfngyqms.css delete mode 100644 apps/user-app-v2/dist/assets/CollectionView-CXUuUCmE.js delete mode 100644 apps/user-app-v2/dist/assets/CompleteProfileView-hH_R3jUX.css delete mode 100644 apps/user-app-v2/dist/assets/CompleteProfileView-j0AONcFj.js delete mode 100644 apps/user-app-v2/dist/assets/CustomerChoiceView-DB7yiqRu.css delete mode 100644 apps/user-app-v2/dist/assets/CustomerChoiceView-zmQgjVme.js delete mode 100644 apps/user-app-v2/dist/assets/DashboardView-BTOUUwpE.js delete mode 100644 apps/user-app-v2/dist/assets/DashboardView-BnSrdKUp.css delete mode 100644 apps/user-app-v2/dist/assets/FavoritesView-BNvXFK2Z.css delete mode 100644 apps/user-app-v2/dist/assets/FavoritesView-BS-C2uMv.js delete mode 100644 apps/user-app-v2/dist/assets/FormItemContext-0CnJhEk0.js delete mode 100644 apps/user-app-v2/dist/assets/HomeView-DSTuecmb.css delete mode 100644 apps/user-app-v2/dist/assets/HomeView-DgtGcpTB.js delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum-BLA2CtIC.woff2 delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum-C2LCNwav.woff delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Black-BFAfOkt4.woff2 delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Black-BZZZWzNZ.woff delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Bold-C8urhp07.woff2 delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Bold-DFiUzN7v.woff delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Light-B637MNLG.woff2 delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Light-Blhumvhg.woff delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Medium-C2CKjrKB.woff2 delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_Medium-DJxlPmBM.woff delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_UltraLight-X2tWVnbe.woff delete mode 100644 apps/user-app-v2/dist/assets/IRANSansWeb_FaNum_UltraLight-hW-WDKY9.woff2 delete mode 100644 apps/user-app-v2/dist/assets/IamCallback-CstyCPgT.js delete mode 100644 apps/user-app-v2/dist/assets/KeyCode-C7e-XTEK.js delete mode 100644 apps/user-app-v2/dist/assets/LoginRegisterView-Cc9V9cq7.js delete mode 100644 apps/user-app-v2/dist/assets/LoginRegisterView-DIgrvcKn.css delete mode 100644 apps/user-app-v2/dist/assets/NewestView-CRqVtDuM.css delete mode 100644 apps/user-app-v2/dist/assets/NewestView-foURH8az.js delete mode 100644 apps/user-app-v2/dist/assets/NotificationsView-AysksH6v.js delete mode 100644 apps/user-app-v2/dist/assets/NotificationsView-BYJ2kMU3.css delete mode 100644 apps/user-app-v2/dist/assets/OrdersView-D-jf8PUm.js delete mode 100644 apps/user-app-v2/dist/assets/OrdersView-DNKGvr4J.css delete mode 100644 apps/user-app-v2/dist/assets/PageBar-BBMNYL0j.js delete mode 100644 apps/user-app-v2/dist/assets/PageBar-DJWT4eaj.css delete mode 100644 apps/user-app-v2/dist/assets/ProductCard-C0a9p2bL.js delete mode 100644 apps/user-app-v2/dist/assets/ProductCard-D6-KxSf7.css delete mode 100644 apps/user-app-v2/dist/assets/ProfileView-CRrMEcnO.css delete mode 100644 apps/user-app-v2/dist/assets/ProfileView-jxoFJaTe.js delete mode 100644 apps/user-app-v2/dist/assets/RateStrip-B00WoPCp.css delete mode 100644 apps/user-app-v2/dist/assets/RateStrip-yK7NvWwz.js delete mode 100644 apps/user-app-v2/dist/assets/ReportView-BrhJZMTH.css delete mode 100644 apps/user-app-v2/dist/assets/ReportView-DRQCm5Pz.js delete mode 100644 apps/user-app-v2/dist/assets/SearchInput-BYt0pCew.js delete mode 100644 apps/user-app-v2/dist/assets/SearchInput-DEfgrsbu.css delete mode 100644 apps/user-app-v2/dist/assets/SearchView-B8CO_3LB.css delete mode 100644 apps/user-app-v2/dist/assets/SearchView-BIw5FNh3.js delete mode 100644 apps/user-app-v2/dist/assets/SectionHead-CDGrZss6.css delete mode 100644 apps/user-app-v2/dist/assets/SectionHead-LafpWeqY.js delete mode 100644 apps/user-app-v2/dist/assets/TransactionsView-BfQHBrDd.js delete mode 100644 apps/user-app-v2/dist/assets/TransactionsView-QJUT0Agr.css delete mode 100644 apps/user-app-v2/dist/assets/brand-logo-c8-B3-lR.png delete mode 100644 apps/user-app-v2/dist/assets/catalogStore-CR1VkPNU.js delete mode 100644 apps/user-app-v2/dist/assets/classCallCheck-BwcnXnXD.js delete mode 100644 apps/user-app-v2/dist/assets/favoritEmpty-kbtPAdi5.svg delete mode 100644 apps/user-app-v2/dist/assets/filters-qWhZyCzD.js delete mode 100644 apps/user-app-v2/dist/assets/index-BEKTkTDh.js delete mode 100644 apps/user-app-v2/dist/assets/index-BMHplzPz.js delete mode 100644 apps/user-app-v2/dist/assets/index-C3cFbOta.css delete mode 100644 apps/user-app-v2/dist/assets/index-D8i4h-PU.js delete mode 100644 apps/user-app-v2/dist/assets/raf-nDFcuFT6.js delete mode 100644 apps/user-app-v2/dist/assets/shipping-and-delivery-CyUGL93q.png delete mode 100644 apps/user-app-v2/dist/assets/sports-and-competition-ao926_SX.png delete mode 100644 apps/user-app-v2/dist/assets/usePagedProducts-Bcf85uEP.js delete mode 100644 apps/user-app-v2/dist/assets/workbox-window.prod.es5-BqEJf4Xk.js delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_bold-B1U8HUd_.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_bold-BgJhv14C.ttf delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_bold-DiCmzWh_.woff delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_fat-ByLTFLyk.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_fat-D7l80IzQ.ttf delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_heavy-DcWv4PAq.woff delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_heavy-DcdOma-5.ttf delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_heavy-h9lE53XZ.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_light-BVC5pEtm.ttf delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_light-DBLK7lys.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_light-MBz7xfzX.woff delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_medium-C7lE-mP3.woff delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_medium-K0xA3c9N.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_medium-udXv5Dbe.ttf delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_regular-5O8oud7N.ttf delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_regular-D-3AgpAQ.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_regular-DYu11jPk.woff delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_thin-BUP5N_wR.woff delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_thin-DdtkSAK0.eot delete mode 100644 apps/user-app-v2/dist/assets/yekan_bakh_fanum_thin-wM_3S6d2.ttf delete mode 100644 apps/user-app-v2/dist/bale.png delete mode 100644 apps/user-app-v2/dist/favicon.ico delete mode 100644 apps/user-app-v2/dist/icon-192.png delete mode 100644 apps/user-app-v2/dist/icon-512.png delete mode 100644 apps/user-app-v2/dist/img/brand-logo.png delete mode 100644 apps/user-app-v2/dist/img/brand-logo.webp delete mode 100644 apps/user-app-v2/dist/img/products/bracelets-0.svg delete mode 100644 apps/user-app-v2/dist/img/products/bracelets-1.svg delete mode 100644 apps/user-app-v2/dist/img/products/bracelets-2.svg delete mode 100644 apps/user-app-v2/dist/img/products/bracelets-3.svg delete mode 100644 apps/user-app-v2/dist/img/products/bracelets-4.svg delete mode 100644 apps/user-app-v2/dist/img/products/bracelets-5.svg delete mode 100644 apps/user-app-v2/dist/img/products/coins-0.svg delete mode 100644 apps/user-app-v2/dist/img/products/coins-1.svg delete mode 100644 apps/user-app-v2/dist/img/products/coins-2.svg delete mode 100644 apps/user-app-v2/dist/img/products/coins-3.svg delete mode 100644 apps/user-app-v2/dist/img/products/coins-4.svg delete mode 100644 apps/user-app-v2/dist/img/products/coins-5.svg delete mode 100644 apps/user-app-v2/dist/img/products/earrings-0.svg delete mode 100644 apps/user-app-v2/dist/img/products/earrings-1.svg delete mode 100644 apps/user-app-v2/dist/img/products/earrings-2.svg delete mode 100644 apps/user-app-v2/dist/img/products/earrings-3.svg delete mode 100644 apps/user-app-v2/dist/img/products/earrings-4.svg delete mode 100644 apps/user-app-v2/dist/img/products/earrings-5.svg delete mode 100644 apps/user-app-v2/dist/img/products/necklaces-0.svg delete mode 100644 apps/user-app-v2/dist/img/products/necklaces-1.svg delete mode 100644 apps/user-app-v2/dist/img/products/necklaces-2.svg delete mode 100644 apps/user-app-v2/dist/img/products/necklaces-3.svg delete mode 100644 apps/user-app-v2/dist/img/products/necklaces-4.svg delete mode 100644 apps/user-app-v2/dist/img/products/necklaces-5.svg delete mode 100644 apps/user-app-v2/dist/img/products/rings-0.svg delete mode 100644 apps/user-app-v2/dist/img/products/rings-1.svg delete mode 100644 apps/user-app-v2/dist/img/products/rings-2.svg delete mode 100644 apps/user-app-v2/dist/img/products/rings-3.svg delete mode 100644 apps/user-app-v2/dist/img/products/rings-4.svg delete mode 100644 apps/user-app-v2/dist/img/products/rings-5.svg delete mode 100644 apps/user-app-v2/dist/index.html delete mode 100644 apps/user-app-v2/dist/manifest.json delete mode 100644 apps/user-app-v2/dist/manifest.webmanifest delete mode 100644 apps/user-app-v2/dist/sw.js delete mode 100644 apps/user-app-v2/dist/version.json delete mode 100644 apps/user-app-v2/dist/whatsapp.png delete mode 100644 apps/user-app-v2/index.html delete mode 100644 apps/user-app-v2/nginx.conf delete mode 100644 apps/user-app-v2/package.json delete mode 100644 apps/user-app-v2/postcss.config.js delete mode 100644 apps/user-app-v2/public/bale.png delete mode 100644 apps/user-app-v2/public/favicon.ico delete mode 100644 apps/user-app-v2/public/icon-192.png delete mode 100644 apps/user-app-v2/public/icon-512.png delete mode 100644 apps/user-app-v2/public/img/brand-logo.png delete mode 100644 apps/user-app-v2/public/img/brand-logo.webp delete mode 100644 apps/user-app-v2/public/img/no-items.png delete mode 100644 apps/user-app-v2/public/img/products/bracelets-0.svg delete mode 100644 apps/user-app-v2/public/img/products/bracelets-1.svg delete mode 100644 apps/user-app-v2/public/img/products/bracelets-2.svg delete mode 100644 apps/user-app-v2/public/img/products/bracelets-3.svg delete mode 100644 apps/user-app-v2/public/img/products/bracelets-4.svg delete mode 100644 apps/user-app-v2/public/img/products/bracelets-5.svg delete mode 100644 apps/user-app-v2/public/img/products/coins-0.svg delete mode 100644 apps/user-app-v2/public/img/products/coins-1.svg delete mode 100644 apps/user-app-v2/public/img/products/coins-2.svg delete mode 100644 apps/user-app-v2/public/img/products/coins-3.svg delete mode 100644 apps/user-app-v2/public/img/products/coins-4.svg delete mode 100644 apps/user-app-v2/public/img/products/coins-5.svg delete mode 100644 apps/user-app-v2/public/img/products/earrings-0.svg delete mode 100644 apps/user-app-v2/public/img/products/earrings-1.svg delete mode 100644 apps/user-app-v2/public/img/products/earrings-2.svg delete mode 100644 apps/user-app-v2/public/img/products/earrings-3.svg delete mode 100644 apps/user-app-v2/public/img/products/earrings-4.svg delete mode 100644 apps/user-app-v2/public/img/products/earrings-5.svg delete mode 100644 apps/user-app-v2/public/img/products/necklaces-0.svg delete mode 100644 apps/user-app-v2/public/img/products/necklaces-1.svg delete mode 100644 apps/user-app-v2/public/img/products/necklaces-2.svg delete mode 100644 apps/user-app-v2/public/img/products/necklaces-3.svg delete mode 100644 apps/user-app-v2/public/img/products/necklaces-4.svg delete mode 100644 apps/user-app-v2/public/img/products/necklaces-5.svg delete mode 100644 apps/user-app-v2/public/img/products/rings-0.svg delete mode 100644 apps/user-app-v2/public/img/products/rings-1.svg delete mode 100644 apps/user-app-v2/public/img/products/rings-2.svg delete mode 100644 apps/user-app-v2/public/img/products/rings-3.svg delete mode 100644 apps/user-app-v2/public/img/products/rings-4.svg delete mode 100644 apps/user-app-v2/public/img/products/rings-5.svg delete mode 100644 apps/user-app-v2/public/manifest.json delete mode 100644 apps/user-app-v2/public/whatsapp.png delete mode 100644 apps/user-app-v2/src/App.vue delete mode 100644 apps/user-app-v2/src/api/cachedReads.ts delete mode 100644 apps/user-app-v2/src/api/client.ts delete mode 100644 apps/user-app-v2/src/assets/img/1020.jpg delete mode 100644 apps/user-app-v2/src/assets/img/Vector.svg delete mode 100644 apps/user-app-v2/src/assets/img/brand-logo.png delete mode 100644 apps/user-app-v2/src/assets/img/empty/cartEmpty.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/customerEmpty.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/dialogEmpty1.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/dialogEmpty2.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/dialogEmpty3.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/dialogEmpty4.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/dialogEmpty5.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/emp_after_search.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/emp_basket.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/emp_before_search.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/emp_favorite.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/emp_notification.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/emp_search.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/favoritEmpty.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/gozareshEmpty.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/ordersEmpty.svg delete mode 100644 apps/user-app-v2/src/assets/img/empty/transactionEmpty.svg delete mode 100644 apps/user-app-v2/src/assets/img/no-items.png delete mode 100644 apps/user-app-v2/src/assets/img/order-open.png delete mode 100644 apps/user-app-v2/src/assets/img/pattern.svg delete mode 100644 apps/user-app-v2/src/assets/img/pattern2.svg delete mode 100644 apps/user-app-v2/src/assets/img/pattern3.svg delete mode 100644 apps/user-app-v2/src/assets/img/registerDelay.svg delete mode 100644 apps/user-app-v2/src/assets/img/shipping-and-delivery.png delete mode 100644 apps/user-app-v2/src/assets/img/sports-and-competition.png delete mode 100644 apps/user-app-v2/src/assets/styles/fonts.less delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum.woff2 delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Black.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Black.woff2 delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Bold.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Bold.woff2 delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Light.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Light.woff2 delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Medium.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_Medium.woff2 delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_UltraLight.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/iransans/IRANSansWeb_FaNum_UltraLight.woff2 delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_bold.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_bold.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_bold.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_fat.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_fat.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_fat.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_hairline.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_hairline.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_hairline.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_heavy.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_heavy.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_heavy.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_light.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_light.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_light.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_medium.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_medium.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_medium.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_regular.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_regular.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_regular.woff delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_thin.eot delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_thin.ttf delete mode 100644 apps/user-app-v2/src/assets/styles/fonts/yekan_bakh_fanum_thin.woff delete mode 100644 apps/user-app-v2/src/assets/styles/style.less delete mode 100644 apps/user-app-v2/src/assets/styles/tailwind.css delete mode 100644 apps/user-app-v2/src/brand.ts delete mode 100644 apps/user-app-v2/src/components/AppUpdateGate.vue delete mode 100644 apps/user-app-v2/src/components/EmptyState.vue delete mode 100644 apps/user-app-v2/src/components/Spinner.vue delete mode 100644 apps/user-app-v2/src/components/expert/ActingAsBar.vue delete mode 100644 apps/user-app-v2/src/components/home/CategoryGrid.vue delete mode 100644 apps/user-app-v2/src/components/home/HeroCarousel.vue delete mode 100644 apps/user-app-v2/src/components/home/ProductCarousel.vue delete mode 100644 apps/user-app-v2/src/components/home/ProductPanel.vue delete mode 100644 apps/user-app-v2/src/components/home/RateStrip.vue delete mode 100644 apps/user-app-v2/src/components/home/SectionHead.vue delete mode 100644 apps/user-app-v2/src/components/icon/Icon.vue delete mode 100644 apps/user-app-v2/src/components/icon/icons.json delete mode 100644 apps/user-app-v2/src/components/input/OtpInput.vue delete mode 100644 apps/user-app-v2/src/components/input/SingleOtpInput.vue delete mode 100644 apps/user-app-v2/src/components/product/CartItem.vue delete mode 100644 apps/user-app-v2/src/components/product/GallerySlider.vue delete mode 100644 apps/user-app-v2/src/components/product/OrderCard.vue delete mode 100644 apps/user-app-v2/src/components/product/OrderItemCard.vue delete mode 100644 apps/user-app-v2/src/components/product/ProductCard.vue delete mode 100644 apps/user-app-v2/src/components/product/ProductMorph.vue delete mode 100644 apps/user-app-v2/src/components/product/SingleProduct.vue delete mode 100644 apps/user-app-v2/src/components/search/Filters.vue delete mode 100644 apps/user-app-v2/src/components/search/SearchInput.vue delete mode 100644 apps/user-app-v2/src/components/ui/AppPullRefresh.vue delete mode 100644 apps/user-app-v2/src/components/ui/Container.vue delete mode 100644 apps/user-app-v2/src/components/ui/DropDown.vue delete mode 100644 apps/user-app-v2/src/components/ui/IslandSheet.vue delete mode 100644 apps/user-app-v2/src/components/ui/Navigation.vue delete mode 100644 apps/user-app-v2/src/components/ui/PageBar.vue delete mode 100644 apps/user-app-v2/src/components/ui/RefreshOverlay.vue delete mode 100644 apps/user-app-v2/src/components/ui/ScrollFetchSearch.vue delete mode 100644 apps/user-app-v2/src/components/ui/SheetArt.vue delete mode 100644 apps/user-app-v2/src/components/ui/ToastCard.vue delete mode 100644 apps/user-app-v2/src/components/ui/ToastHost.vue delete mode 100644 apps/user-app-v2/src/components/ui/ToggleSwitch.vue delete mode 100644 apps/user-app-v2/src/components/upload/SingleImageUploader.vue delete mode 100644 apps/user-app-v2/src/composables/useAppUpdate.ts delete mode 100644 apps/user-app-v2/src/composables/useOrderItemProduct.ts delete mode 100644 apps/user-app-v2/src/composables/usePagedProducts.ts delete mode 100644 apps/user-app-v2/src/composables/useProduct.ts delete mode 100644 apps/user-app-v2/src/composables/useProductDetail.ts delete mode 100644 apps/user-app-v2/src/composables/useProductMorph.ts delete mode 100644 apps/user-app-v2/src/composables/useProducts.ts delete mode 100644 apps/user-app-v2/src/composables/useToast.ts delete mode 100644 apps/user-app-v2/src/env.d.ts delete mode 100644 apps/user-app-v2/src/layout/FullPageLayout.vue delete mode 100644 apps/user-app-v2/src/layout/MasterLayout.vue delete mode 100644 apps/user-app-v2/src/main.ts delete mode 100644 apps/user-app-v2/src/router/index.ts delete mode 100644 apps/user-app-v2/src/stores/appearanceStore.ts delete mode 100644 apps/user-app-v2/src/stores/cartStore.ts delete mode 100644 apps/user-app-v2/src/stores/catalogStore.ts delete mode 100644 apps/user-app-v2/src/stores/configStore.ts delete mode 100644 apps/user-app-v2/src/stores/favoritesStore.ts delete mode 100644 apps/user-app-v2/src/stores/filtersStore.ts delete mode 100644 apps/user-app-v2/src/stores/navStore.ts delete mode 100644 apps/user-app-v2/src/stores/queryCache.ts delete mode 100644 apps/user-app-v2/src/stores/session.ts delete mode 100644 apps/user-app-v2/src/stores/transitionStore.ts delete mode 100644 apps/user-app-v2/src/stores/wageQuoteStore.ts delete mode 100644 apps/user-app-v2/src/stores/windowDataStore.ts delete mode 100644 apps/user-app-v2/src/sw.ts delete mode 100644 apps/user-app-v2/src/types/moment-jalaali-shim.d.ts delete mode 100644 apps/user-app-v2/src/types/swiper-shim.d.ts delete mode 100644 apps/user-app-v2/src/utils/checkAccess.ts delete mode 100644 apps/user-app-v2/src/utils/filters.ts delete mode 100644 apps/user-app-v2/src/utils/orderStatus.ts delete mode 100644 apps/user-app-v2/src/utils/validator.ts delete mode 100644 apps/user-app-v2/src/views/CartView.vue delete mode 100644 apps/user-app-v2/src/views/HomeView.vue delete mode 100644 apps/user-app-v2/src/views/NewestView.vue delete mode 100644 apps/user-app-v2/src/views/expert/ChildOrdersView.vue delete mode 100644 apps/user-app-v2/src/views/expert/CustomerChoiceView.vue delete mode 100644 apps/user-app-v2/src/views/report/ReportDocument.vue delete mode 100644 apps/user-app-v2/src/views/report/ReportView.vue delete mode 100644 apps/user-app-v2/src/views/search/CollectionView.vue delete mode 100644 apps/user-app-v2/src/views/search/SearchView.vue delete mode 100644 apps/user-app-v2/src/views/user/AppearanceView.vue delete mode 100644 apps/user-app-v2/src/views/user/CompleteProfileView.vue delete mode 100644 apps/user-app-v2/src/views/user/DashboardView.vue delete mode 100644 apps/user-app-v2/src/views/user/FavoritesView.vue delete mode 100644 apps/user-app-v2/src/views/user/IamCallback.vue delete mode 100644 apps/user-app-v2/src/views/user/LoginRegisterView.vue delete mode 100644 apps/user-app-v2/src/views/user/LoginView.vue delete mode 100644 apps/user-app-v2/src/views/user/NotificationsView.vue delete mode 100644 apps/user-app-v2/src/views/user/OrdersView.vue delete mode 100644 apps/user-app-v2/src/views/user/ProfileView.vue delete mode 100644 apps/user-app-v2/src/views/user/RegisterView.vue delete mode 100644 apps/user-app-v2/src/views/user/TransactionsView.vue delete mode 100644 apps/user-app-v2/tailwind.config.js delete mode 100644 apps/user-app-v2/themeConfig/appearance.ts delete mode 100644 apps/user-app-v2/themeConfig/colors.dark.json delete mode 100644 apps/user-app-v2/themeConfig/colors.json delete mode 100644 apps/user-app-v2/themeConfig/themeConfig.ts delete mode 100644 apps/user-app-v2/tsconfig.json delete mode 100644 apps/user-app-v2/vite.config.ts create mode 100644 apps/user-app/src/stores/notificationsStore.ts create mode 100644 apps/user-app/src/utils/notificationCopy.ts create mode 100644 docs/RIAL-WAGE-PORT.md diff --git a/.env.example b/.env.example index b93b615..eade3c7 100644 --- a/.env.example +++ b/.env.example @@ -20,7 +20,6 @@ DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGR API_PORT=3000 ADMIN_PANEL_PORT=5180 USER_APP_PORT=5181 -USER_APP_V2_PORT=5182 # API Configuration (kept for any tooling that still reads bare PORT) PORT=3000 diff --git a/DELIVERY.md b/DELIVERY.md index 0e0d043..92ca24f 100644 --- a/DELIVERY.md +++ b/DELIVERY.md @@ -196,7 +196,7 @@ container. | `JWT_EXPIRES_IN` | `12h` | Admin token lifetime. | | `JWT_CUSTOMER_EXPIRES_IN` | `30d` | Customer token lifetime. | | `UPLOAD_DIR` | `/storage/uploads` | Where uploaded files are written. | -| `ADMIN_PANEL_PORT`, `USER_APP_PORT`, `USER_APP_V2_PORT` | 5180–5182 | Dev servers only. | +| `ADMIN_PANEL_PORT`, `USER_APP_PORT` | 5180–5181 | Dev servers only. | | `RUN_MIGRATIONS` | `true` | Set `false` to skip the boot-time migration run. | | `RUN_SEED` | `true` | Set `false` to skip seeding. | | `ACCOUNTING_SECRET_KEY` | *(derived from `JWT_SECRET`)* | Encrypts the accounting-software token the admin enters (D27). Set its own long random value; changing it later means re-entering the token. | @@ -240,7 +240,7 @@ pnpm dev # all apps via turbo ``` Ports come from the repo-root `.env` (single source of truth): -API 3000, admin-panel 5180, user-app 5181, user-app-v2 5182. +API 3000, admin-panel 5180, user-app 5181. ### Build @@ -263,8 +263,8 @@ docker compose up -d --build > success. During this delivery's compose run that bundle was four days old and > the container was missing every route added since. Tracked as **DEPLOY-03**. -Services: `db` (Postgres 15), `api` (port 3000), `admin-panel`, `user-app`, -`user-app-v2` (each nginx on port 80). The apps expose no host ports — +Services: `db` (Postgres 15), `api` (port 3000), `admin-panel`, `user-app` +(each nginx on port 80). The apps expose no host ports — Dokploy/Traefik routes to them by domain. Uploads persist in the `api_uploads` volume; without it every previously uploaded image 404s after a redeploy. diff --git a/DOCKER.md b/DOCKER.md index 2515837..22d0e85 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -8,7 +8,7 @@ Dokploy only builds thin images that copy those files (no `pnpm install` on the ```bash pnpm install pnpm build:release -git add -f apps/api/release apps/admin-panel/dist apps/user-app/dist apps/user-app-v2/dist +git add -f apps/api/release apps/admin-panel/dist apps/user-app/dist git commit -m "chore: refresh release artifacts" git push ``` @@ -20,7 +20,6 @@ What this produces: | API | `apps/api/release/app.js` (+ Prisma under `release/vendor`) | `docker.arvancloud.ir/node:20-bookworm` | | Admin | `apps/admin-panel/dist/` | `docker.arvancloud.ir/nginx:latest` | | User | `apps/user-app/dist/` | `docker.arvancloud.ir/nginx:latest` | -| User v2 | `apps/user-app-v2/dist/` | `docker.arvancloud.ir/nginx:latest` | ## Dokploy Environment @@ -46,7 +45,6 @@ different Compose project name for each application. |---|---|---| | `admin-panel` | admin.example.com | **80** | | `user-app` | app.example.com | **80** | -| `user-app-v2` | app-v2.example.com | **80** | | `api` | (optional) | **3000** | Frontends call `/api` on their own domain; nginx proxies to `api:3000`. diff --git a/apps/user-app-v2/dist/img/no-items.png b/apps/admin-panel/public/img/no-items.png similarity index 100% rename from apps/user-app-v2/dist/img/no-items.png rename to apps/admin-panel/public/img/no-items.png diff --git a/apps/admin-panel/src/api/endpoints.ts b/apps/admin-panel/src/api/endpoints.ts index 0beff76..4937469 100644 --- a/apps/admin-panel/src/api/endpoints.ts +++ b/apps/admin-panel/src/api/endpoints.ts @@ -89,6 +89,7 @@ const EXACT: Record = { // ── products (Batch 6) ──────────────────────────────────────────── products: 'admin/products/list', 'product/create': 'admin/products/create', + 'product/categories': 'admin/products/categories', 'get/variants': 'admin/products/variants/list', 'change/percent/count': 'admin/products/change-percent/count', 'change/all': 'admin/products/change-percent/apply', diff --git a/apps/admin-panel/src/utils/orderStatus.ts b/apps/admin-panel/src/utils/orderStatus.ts new file mode 100644 index 0000000..f9a2f3b --- /dev/null +++ b/apps/admin-panel/src/utils/orderStatus.ts @@ -0,0 +1,75 @@ +// Mirrors apps/user-app/src/utils/orderStatus.ts — same labels, blurbs and +// colors so the admin status modal feels like the customer timeline sheet. +import type { Component } from 'vue'; +import { + CarOutlined, + CheckCircleOutlined, + CloseCircleOutlined, + FileDoneOutlined, + GiftOutlined, + InboxOutlined, + PauseCircleOutlined, + SafetyCertificateOutlined, +} from '@ant-design/icons-vue'; + +export const ORDER_STATUS_LABELS: Record = { + SUSPENDED: 'معلق', + PLACED: 'ثبت سفارش', + ADMIN_APPROVED: 'تایید مدیر', + SOURCING: 'در حال تامین', + PREPARING: 'آماده‌سازی', + DELIVERED_TO_AGENT: 'تحویل نماینده', + DELIVERED_TO_CUSTOMER: 'تحویل مشتری', + CANCELLED: 'لغو شده', +}; + +export const ORDER_STATUS_BLURBS: Record = { + SUSPENDED: 'سفارش به‌دلیل سقف اعتبار معلق شد', + PLACED: 'سفارش ثبت و دریافت شد', + ADMIN_APPROVED: 'سفارش توسط مدیر تایید شد', + SOURCING: 'کالا در حال تامین است', + PREPARING: 'سفارش در حال آماده‌سازی است', + DELIVERED_TO_AGENT: 'تحویل به نماینده فروش انجام شد', + DELIVERED_TO_CUSTOMER: 'سفارش به مشتری تحویل شد', + CANCELLED: 'سفارش لغو شده است', +}; + +export const ORDER_STATUS_COLORS: Record = { + SUSPENDED: { font: '#A16207', background: '#A162071F' }, + PLACED: { font: '#3B82F6', background: '#3B82F61F' }, + ADMIN_APPROVED: { font: '#6366F1', background: '#6366F11F' }, + SOURCING: { font: '#EAB308', background: '#EAB3081F' }, + PREPARING: { font: '#F97316', background: '#F973161F' }, + DELIVERED_TO_AGENT: { font: '#06B6D4', background: '#06B6D41F' }, + DELIVERED_TO_CUSTOMER: { font: '#22C55E', background: '#22C55E1F' }, + CANCELLED: { font: '#DC2626', background: '#DC26261F' }, +}; + +export const ORDER_STATUS_ICONS: Record = { + SUSPENDED: PauseCircleOutlined, + PLACED: FileDoneOutlined, + ADMIN_APPROVED: SafetyCertificateOutlined, + SOURCING: InboxOutlined, + PREPARING: GiftOutlined, + DELIVERED_TO_AGENT: CarOutlined, + DELIVERED_TO_CUSTOMER: CheckCircleOutlined, + CANCELLED: CloseCircleOutlined, +}; + +const FALLBACK_COLOR = { font: '#64748B', background: '#64748B1F' }; + +export function orderStatusColor(status: string) { + return ORDER_STATUS_COLORS[status] ?? FALLBACK_COLOR; +} + +export function orderStatusLabel(status: string) { + return ORDER_STATUS_LABELS[status] ?? status; +} + +export function orderStatusBlurb(status: string) { + return ORDER_STATUS_BLURBS[status] ?? ''; +} + +export function orderStatusIcon(status: string) { + return ORDER_STATUS_ICONS[status] ?? FileDoneOutlined; +} diff --git a/apps/admin-panel/src/views/apps/product/AddProduct.vue b/apps/admin-panel/src/views/apps/product/AddProduct.vue index 89b5efb..c3374b2 100644 --- a/apps/admin-panel/src/views/apps/product/AddProduct.vue +++ b/apps/admin-panel/src/views/apps/product/AddProduct.vue @@ -9,8 +9,9 @@ Fields with no column in the redesigned schema are NOT rendered rather than collected and silently dropped — listed in docs/ADMIN-PORT-PLAN.md: - delivery_type, message_long_delivery, offer_day, has_warranty, is_exist, - tags, and the variant colour/rial-wage fields. + delivery_type, message_long_delivery, offer_day, has_warranty, is_exist. + Tags are wired again: chosen from Setting `__list__tags` and stored on + Product.tags; the storefront shows them on list cards only. The image uploaders ARE rendered (unlike the note above once claimed): Product.images is a real ProductImage[] relation and `file/create` is a real, @@ -256,7 +257,7 @@

دسته‌بندی

-

دسته، برند و سینی‌های محصول

+

دسته، برند، سینی و برچسب‌های محصول

@@ -268,7 +269,7 @@ - + {{ b.title }} @@ -277,7 +278,7 @@ - + + + + +
@@ -529,6 +541,7 @@ const activeGalleryTab = ref<'site' | 'mobile'>('site'); const brands = ref<{ id: string; title: string }[]>([]); const categories = ref<{ id: string; title: string }[]>([]); const collections = ref<{ id: string; title: string }[]>([]); +const tagOptions = ref([]); const form = reactive>({ title: '', @@ -537,6 +550,7 @@ const form = reactive>({ category_id: undefined, brand_id: undefined, ciny_ids: [] as string[], + tags: [] as string[], body_html: '', is_active: true, indicator_id: null as string | null, @@ -715,11 +729,12 @@ async function handleSubmit() { onMounted(async () => { try { - const [b, c, col, colorsRes] = await Promise.all([ + const [b, c, col, colorsRes, tagsRes] = await Promise.all([ api.get('brand'), api.post('category'), users.isSuperAdmin ? api.get('admin/products/collections') : Promise.resolve({ data: [] }), api.get('admin/products/colors').catch(() => ({ data: [] })), + api.get('const/__list__tags').catch(() => ({ data: [] })), ]); brands.value = b.data; categories.value = (c.data.rows ?? c.data).map((x: any) => ({ @@ -729,6 +744,7 @@ onMounted(async () => { })); collections.value = col.data; colorOptions.value = colorsRes.data ?? []; + tagOptions.value = Array.isArray(tagsRes.data) ? tagsRes.data.map(String) : []; } catch (e) { console.log(e); } @@ -746,6 +762,7 @@ onMounted(async () => { category_id: data.category?.id ?? undefined, brand_id: data.brand?.id ?? undefined, ciny_ids: data.ciny_ids ?? [], + tags: Array.isArray(data.tags) ? data.tags : [], body_html: data.body_html ?? '', is_active: data.is_active ?? true, indicator_id: data.indicator_id ?? null, diff --git a/apps/admin-panel/src/views/apps/product/ProductList.vue b/apps/admin-panel/src/views/apps/product/ProductList.vue index 00ecec3..43f0bcc 100644 --- a/apps/admin-panel/src/views/apps/product/ProductList.vue +++ b/apps/admin-panel/src/views/apps/product/ProductList.vue @@ -29,6 +29,13 @@ - + + @@ -82,6 +89,12 @@ {{ tempRow.category?.title || '-' }} + + + - + {{ tempRow.show_type_str }} {{ tempRow.variants_all?.length ?? tempRow.variants_count ?? 0 }} @@ -184,6 +197,16 @@ function toEdit(id: string) { border-radius: 4px; } +.product-tags { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + +.text-muted { + color: rgba(0, 0, 0, 0.35); +} + @media (max-width: 575px) { /* the actions sit in the card header on phones; a fixed 12rem would crowd the title */ .w-48 { diff --git a/apps/admin-panel/src/views/apps/product/productListModel.ts b/apps/admin-panel/src/views/apps/product/productListModel.ts index ade7a1b..3143136 100644 --- a/apps/admin-panel/src/views/apps/product/productListModel.ts +++ b/apps/admin-panel/src/views/apps/product/productListModel.ts @@ -15,6 +15,7 @@ export function buildProductListModel(withShowType = true): XTbl { // legacy key is 'category.collection.title'; the mapping layer aliases it tbl.add(new Xtc('category.collection.title', 'دسته بندی').filterText()); tbl.add(new Xtc('product_code', 'کد محصول').filterText()); + tbl.add(new Xtc('tags', 'برچسب‌ها').renderSlot('tags').noSort()); if (withShowType) { tbl.add( new Xtc('show_type', 'نوع نمایش') diff --git a/apps/admin-panel/src/views/customer/omde/omdeListModel.ts b/apps/admin-panel/src/views/customer/omde/omdeListModel.ts index 8249020..bb3a505 100644 --- a/apps/admin-panel/src/views/customer/omde/omdeListModel.ts +++ b/apps/admin-panel/src/views/customer/omde/omdeListModel.ts @@ -35,7 +35,7 @@ export function buildOmdeListModel(source: OmdeSourceKey): XTbl { tbl.add(new Xtc('fname', 'نام').filterText().hidden()); tbl.add(new Xtc('lname', 'نام خانوادگی').filterText().hidden()); tbl.add(new Xtc('name', 'نام و نام خانوادگی').filterText()); - tbl.add(new Xtc('mobile', 'موبایل').filterText().hidden().noSort()); + tbl.add(new Xtc('mobile', 'موبایل').filterText().noSort()); tbl.add( new Xtc('city_id', 'شهر') .hidden() diff --git a/apps/admin-panel/src/views/customer/reagentList/ReagentListModel.ts b/apps/admin-panel/src/views/customer/reagentList/ReagentListModel.ts index cac3fe9..8c8cce5 100644 --- a/apps/admin-panel/src/views/customer/reagentList/ReagentListModel.ts +++ b/apps/admin-panel/src/views/customer/reagentList/ReagentListModel.ts @@ -18,7 +18,7 @@ export function buildReagentListModel(): XTbl { tbl.add(new Xtc('name', 'نام و نام خانوادگی').filterText()); // legacy adds 'name' a second time, hidden — preserved tbl.add(new Xtc('name', 'نام').filterText().hidden()); - tbl.add(new Xtc('mobile', 'موبایل').filterText().hidden().noSort()); + tbl.add(new Xtc('mobile', 'موبایل').filterText().noSort()); tbl.add( new Xtc('city_id', 'شهر') .hidden() diff --git a/apps/admin-panel/src/views/order/List.vue b/apps/admin-panel/src/views/order/List.vue index 014ee57..28627f8 100644 --- a/apps/admin-panel/src/views/order/List.vue +++ b/apps/admin-panel/src/views/order/List.vue @@ -51,103 +51,60 @@ - - - -
-
{{ item.title }}
-
-
-
- {{ formatDate(item.uaj) }} -
- - - حذف وضعیت - -
-
-
- - ثبت وضعیت -
-
{{ item.note }}
-
-
-
+ + - - -
- - - {{ tempRow.customer.fname }} {{ tempRow.customer.lname }} - - - {{ tempRow.customer.phone }} - - {{ formatDate(tempRow.caj) }} - {{ tempRow.sts_str }} - - - -
- - - {{ item.title }} - - {{ item.variant_title }} - - - {{ item.grams }} - - - - {{ item.qty }} - - -
{{ item.note }}
-
-
- -
-
-
- + + + @@ -160,11 +117,13 @@ import { computed, ref } from 'vue'; import { message } from 'ant-design-vue'; import XTable from '../../components/x-table/XTable.vue'; import TooltipBtn from '../../components/tooltip-btn/TooltipBtn.vue'; +import OrderDetailBody from './OrderDetailBody.vue'; +import OrderStatusTimeline from './OrderStatusTimeline.vue'; import { buildOrderListModel } from './orderListModel'; import { useUsersStore } from '../../stores/users'; import { isBranch } from '../../utils'; import api from '../../api/client'; -import { jdate, priceUnit } from '../../utils/filters'; +import { priceUnit } from '../../utils/filters'; const users = useUsersStore(); const hasPermission = (rid: string) => Boolean(users.hasPermission(rid)); @@ -173,17 +132,16 @@ const model = buildOrderListModel(); const tbl = ref<{ fetch: () => Promise } | null>(null); const tempRow = ref | undefined>(undefined); +const detailSnapshot = ref(''); const visibleList = ref(false); const visibleSts = ref(false); const editMode = ref(false); +const saving = ref(false); +const addVariantId = ref(''); +const addQty = ref(1); const is_branch = computed(() => isBranch()); - -const formatDate = (v: string | null) => (v ? jdate(v) : ''); - -function getColorSts(row: { proceed?: boolean }) { - return row.proceed ? 'green' : 'gray'; -} +const canEditOrder = computed(() => hasPermission('order.list.view.edit')); async function showSts(row: Record) { // legacy: branch orders have no editable status timeline @@ -200,12 +158,8 @@ async function loadDetail(id: string) { /** * Both handlers receive one ACTIVITY entry from the timeline - * (`{status, title, proceed, uaj, note}` — admin-orders.service.ts:249-258), - * which carries no order id. Posting that object straight through left - * `orderId` missing and UpdateOrderStatusDto rejected every call with 400, so - * neither "ثبت وضعیت" nor "حذف وضعیت" worked on this screen at all. The id - * comes from `tempRow`, the order loaded when the dialog opened. OmdeList.vue - * already built its body this way (OmdeList.vue:187). + * (`{status, title, proceed, uaj, note}`), which carries no order id. + * The id comes from `tempRow`, the order loaded when the dialog opened. */ async function setSts(row: Record) { try { @@ -238,21 +192,122 @@ async function removeSts(row: Record) { } } -async function editRow() { +function closeDetail() { + visibleList.value = false; + editMode.value = false; +} + +function cancelEdit() { + if (detailSnapshot.value) { + try { + tempRow.value = JSON.parse(detailSnapshot.value); + } catch { + /* keep */ + } + } + editMode.value = false; +} + +function removeLine(index: number) { + if (!tempRow.value?.items) return; + if (tempRow.value.items.length <= 1) { + message.warning('حداقل یک آیتم باید در سفارش بماند'); + return; + } + tempRow.value.items.splice(index, 1); +} + +function onAddLine(payload: { + variantId: string; + qty: number; + title?: string; + variantTitle?: string; + grams?: number; + wagePercent?: number; + flatRialCharge?: number; + image?: string | null; +}) { + const vid = payload.variantId.trim(); + if (!vid) { + message.warning('یک تنوع انتخاب کنید'); + return; + } + if (!tempRow.value) return; + tempRow.value.items.push({ + productVariantId: vid, + title: payload.title ?? 'آیتم جدید', + variant_title: payload.variantTitle ?? vid, + qty: payload.qty || 1, + grams: payload.grams ?? 0, + flatRialCharge: payload.flatRialCharge ?? 0, + wagePercent: payload.wagePercent, + rash: payload.grams ?? 0, + image: payload.image ?? null, + }); + addVariantId.value = ''; + addQty.value = 1; +} + +async function submitEdit() { + if (!tempRow.value?.id) return; + const items = (tempRow.value.items ?? []) + .filter((it: any) => it.productVariantId) + .map((it: any) => ({ + productVariantId: it.productVariantId, + quantity: Number(it.qty) || 1, + grams: Number(it.grams) || undefined, + flatRialCharge: Number(it.flatRialCharge) || 0, + rashWeightGrams: it.rash != null ? Number(it.rash) : undefined, + wagePercent: it.wagePercent != null ? Number(it.wagePercent) : undefined, + discountPercent: it.discountPercent != null ? Number(it.discountPercent) : undefined, + })); + if (!items.length) { + message.error('حداقل یک آیتم لازم است'); + return; + } + saving.value = true; try { - // Legacy's PUT call is commented out in the original too — it only toggles - // the UI and re-fetches. Ported as-is; the edit is not persisted. - editMode.value = !editMode.value; - visibleList.value = !visibleList.value; - message.info('ویرایش موفق آمیز'); + await api.post('admin/orders/edit/propose', { orderId: tempRow.value.id, items }); + message.success('پیشنهاد ویرایش ثبت شد؛ پیامک برای مشتری ارسال می‌شود'); + editMode.value = false; + tempRow.value = await loadDetail(tempRow.value.id); + detailSnapshot.value = JSON.stringify(tempRow.value); tbl.value?.fetch(); - } catch (e) { - message.error('خطا در ویرایش'); + } catch (e: any) { + message.error(e?.response?.data?.message ?? 'خطا در ثبت ویرایش'); + } finally { + saving.value = false; + } +} + +async function forceApplyEdit() { + if (!tempRow.value?.id) return; + try { + await api.post('admin/orders/edit/force-apply', { orderId: tempRow.value.id }); + message.success('ویرایش به‌صورت اجباری اعمال شد'); + tempRow.value = await loadDetail(tempRow.value.id); + tbl.value?.fetch(); + } catch (e: any) { + message.error(e?.response?.data?.message ?? 'خطا در اعمال'); + } +} + +async function discardEdit() { + if (!tempRow.value?.id) return; + try { + await api.post('admin/orders/edit/discard', { orderId: tempRow.value.id }); + message.success('پیشنهاد ویرایش لغو شد'); + tempRow.value = await loadDetail(tempRow.value.id); + tbl.value?.fetch(); + } catch (e: any) { + message.error(e?.response?.data?.message ?? 'خطا در لغو'); } } async function viewOrder(row: Record) { tempRow.value = await loadDetail(row.id); + detailSnapshot.value = JSON.stringify(tempRow.value); + editMode.value = false; visibleList.value = true; } diff --git a/apps/admin-panel/src/views/order/OmdeList.vue b/apps/admin-panel/src/views/order/OmdeList.vue index 2ded720..f38d74e 100644 --- a/apps/admin-panel/src/views/order/OmdeList.vue +++ b/apps/admin-panel/src/views/order/OmdeList.vue @@ -55,81 +55,61 @@ - - - -
-
{{ item.title }}
-
-
-
- {{ formatDate(item.uaj) }} -
- - - حذف وضعیت - -
-
-
- - ثبت وضعیت -
-
{{ item.note }}
-
-
-
+ + - - -
- - - {{ tempRow.customer.fname }} {{ tempRow.customer.lname }} - - {{ tempRow.customer.phone }} - {{ formatDate(tempRow.caj) }} - {{ tempRow.sts_str }} - - - -
- - - {{ item.title }} - - {{ item.variant_title }} - - {{ item.grams }} - - - {{ item.qty }} - - - -
-
-
- + + + @@ -137,14 +117,15 @@ + + diff --git a/apps/admin-panel/src/views/order/OrderStatusTimeline.vue b/apps/admin-panel/src/views/order/OrderStatusTimeline.vue new file mode 100644 index 0000000..0cf9009 --- /dev/null +++ b/apps/admin-panel/src/views/order/OrderStatusTimeline.vue @@ -0,0 +1,396 @@ + + + + + + diff --git a/apps/admin-panel/src/views/order/TaminList.vue b/apps/admin-panel/src/views/order/TaminList.vue index 5f807de..216da37 100644 --- a/apps/admin-panel/src/views/order/TaminList.vue +++ b/apps/admin-panel/src/views/order/TaminList.vue @@ -42,78 +42,28 @@ - - - -
-
{{ item.title }}
-
-
-
- {{ formatDate(item.uaj) }} -
- - - حذف وضعیت - -
-
-
- - ثبت وضعیت -
-
{{ item.note }}
-
-
-
+ + - -
- - - {{ tempRow.customer.fname }} {{ tempRow.customer.lname }} - - {{ tempRow.customer.phone }} - {{ formatDate(tempRow.caj) }} - {{ tempRow.sts_str }} - - - -
- - - {{ item.title }} - - {{ item.variant_title }} - - {{ item.grams }} - - - {{ item.qty }} - - - -
-
-
- + +