sme-pos-package 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/dist/index.d.mts +37 -2
  2. package/dist/index.mjs +17 -104
  3. package/dist/index.mjs.map +1 -1
  4. package/dist/tailwind.preset.d.mts +27 -0
  5. package/dist/tailwind.preset.mjs +2 -0
  6. package/dist/tailwind.preset.mjs.map +1 -0
  7. package/package.json +18 -30
  8. package/public/assets/images/bank-logos.png +0 -0
  9. package/public/assets/images/banner1.png +0 -0
  10. package/public/assets/images/banner2.png +0 -0
  11. package/public/assets/images/banner3.png +0 -0
  12. package/public/assets/images/banner4.png +0 -0
  13. package/public/assets/images/cashier.svg +9 -0
  14. package/public/assets/images/empty-cart.png +0 -0
  15. package/public/assets/images/empty-table-state.png +0 -0
  16. package/public/assets/images/layout-display/left-layout.png +0 -0
  17. package/public/assets/images/layout-display/right-layout.png +0 -0
  18. package/public/assets/images/modal-illustration.png +0 -0
  19. package/public/assets/images/order-empty-state.png +0 -0
  20. package/public/assets/images/order.png +0 -0
  21. package/public/assets/images/payment-success-label.png +0 -0
  22. package/public/assets/images/table-empty.png +0 -0
  23. package/public/assets/images/take-away.png +0 -0
  24. package/public/assets/lottie/loading.json +1 -0
  25. package/public/assets/lottie/soft_pos.json +1 -0
  26. package/public/assets/lottie/success.json +1 -0
  27. package/public/config.json +27 -0
  28. package/public/env.json +17 -0
  29. package/src/animations/success.json +9730 -0
  30. package/src/assets/icons/breadcrumbs-icon.tsx +85 -0
  31. package/src/assets/icons/cart-icon.tsx +14 -0
  32. package/src/assets/icons/common.tsx +270 -0
  33. package/src/assets/icons/customer-view-icon.tsx +20 -0
  34. package/src/assets/icons/dining-table.tsx +34 -0
  35. package/src/assets/icons/edit-line-icon.tsx +18 -0
  36. package/src/assets/icons/emenu-icon.tsx +39 -0
  37. package/src/assets/icons/file-close-line-icon.tsx +18 -0
  38. package/src/assets/icons/helper-icon.tsx +84 -0
  39. package/src/assets/icons/home-gear-line-icon.tsx +18 -0
  40. package/src/assets/icons/kanban-icon.tsx +16 -0
  41. package/src/assets/icons/loading-icon.tsx +45 -0
  42. package/src/assets/icons/logout-box-line-icon.tsx +18 -0
  43. package/src/assets/icons/order-icon.tsx +92 -0
  44. package/src/assets/icons/payment-icon.tsx +429 -0
  45. package/src/assets/icons/pincode.tsx +196 -0
  46. package/src/assets/icons/pos-connect-icon.tsx +67 -0
  47. package/src/assets/icons/pos-device-icon.tsx +52 -0
  48. package/src/assets/icons/pos-icon.tsx +75 -0
  49. package/src/assets/icons/printer-line-icon.tsx +18 -0
  50. package/src/assets/icons/star-icon.tsx +174 -0
  51. package/src/assets/icons/table-icon.tsx +77 -0
  52. package/src/assets/icons/user-add-line-icon.tsx +33 -0
  53. package/src/assets/icons/user-icon.tsx +65 -0
  54. package/src/components/common/button-action.tsx +46 -0
  55. package/src/components/common/button-icon.tsx +23 -0
  56. package/src/components/common/dropdown/index.tsx +79 -0
  57. package/src/components/common/empty-state.tsx +60 -0
  58. package/src/components/common/header/index.tsx +89 -0
  59. package/src/components/common/header/tabs.tsx +119 -0
  60. package/src/components/common/image.tsx +20 -0
  61. package/src/components/common/input/index.tsx +55 -0
  62. package/src/components/common/input/radio-group.tsx +75 -0
  63. package/src/components/common/input/text-area.tsx +28 -0
  64. package/src/components/common/modal/delete-confirm-modal-container.tsx +65 -0
  65. package/src/components/common/modal/index.ts +2 -0
  66. package/src/components/common/modal/modal-direction.tsx +125 -0
  67. package/src/components/common/modal/modal-header.tsx +37 -0
  68. package/src/components/common/modal/modal-wrapper.tsx +56 -0
  69. package/src/components/common/modal/modal-zoom.tsx +61 -0
  70. package/src/components/common/pagination.tsx +95 -0
  71. package/src/components/common/refresh-button.tsx +28 -0
  72. package/src/components/common/search-bar.tsx +27 -0
  73. package/src/components/common/search.tsx +59 -0
  74. package/src/components/common/skeleton.tsx +7 -0
  75. package/src/components/common/tabs-layout.tsx +98 -0
  76. package/src/components/common/use-check-session.tsx +19 -0
  77. package/src/components/customer-management/add-customer/add-customer-drawer.tsx +286 -0
  78. package/src/components/customer-management/add-customer/address-select.tsx +51 -0
  79. package/src/components/customer-management/choose-customer-drawer.tsx +177 -0
  80. package/src/components/customer-management/customer-info-drawer.tsx +166 -0
  81. package/src/components/customer-management/customer-no-data.tsx +18 -0
  82. package/src/components/emenu/emenu-qr-code.tsx +59 -0
  83. package/src/components/emenu/menu-link.tsx +67 -0
  84. package/src/components/index.ts +8 -0
  85. package/src/components/kanban-template/kitchen-template.tsx +60 -0
  86. package/src/components/kanban-template/pos-order-template.tsx +77 -0
  87. package/src/components/kanban-template/pos-template.tsx +170 -0
  88. package/src/components/kitchen-management/change-status-confirm-modal.tsx +61 -0
  89. package/src/components/kitchen-management/index.ts +1 -0
  90. package/src/components/kitchen-management/kitchen-order/index.tsx +153 -0
  91. package/src/components/kitchen-management/kitchen-order/line.tsx +78 -0
  92. package/src/components/kitchen-management/kitchen-order/state.tsx +52 -0
  93. package/src/components/kitchen-management/kitchen-status.tsx +69 -0
  94. package/src/components/kitchen-management/orders-kitchen-management.tsx +113 -0
  95. package/src/components/order-management/index.tsx +128 -0
  96. package/src/components/order-management/order-actions.tsx +46 -0
  97. package/src/components/order-management/order-detail/header.tsx +37 -0
  98. package/src/components/order-management/order-detail/index.ts +3 -0
  99. package/src/components/order-management/order-detail/information.tsx +96 -0
  100. package/src/components/order-management/order-detail/order-detail.tsx +84 -0
  101. package/src/components/order-management/order-detail/order-line.tsx +56 -0
  102. package/src/components/order-management/order-detail/summary.tsx +221 -0
  103. package/src/components/order-management/order-header.tsx +113 -0
  104. package/src/components/order-management/order-pagination.tsx +49 -0
  105. package/src/components/order-management/order-status.tsx +58 -0
  106. package/src/components/order-management/order-table.tsx +179 -0
  107. package/src/components/order-management/order-tabs.tsx +48 -0
  108. package/src/components/pos-management/add-product-from-barcode/index.tsx +97 -0
  109. package/src/components/pos-management/cart-content/action-line.tsx +81 -0
  110. package/src/components/pos-management/cart-content/cancel-order-line-modal.tsx +41 -0
  111. package/src/components/pos-management/cart-content/cart-item.tsx +173 -0
  112. package/src/components/pos-management/cart-content/cart-items.tsx +130 -0
  113. package/src/components/pos-management/cart-content/draft-orders/draft-order-line.tsx +67 -0
  114. package/src/components/pos-management/cart-content/draft-orders/index.tsx +40 -0
  115. package/src/components/pos-management/cart-content/edit-cart-modal.tsx +11 -0
  116. package/src/components/pos-management/cart-content/index.tsx +260 -0
  117. package/src/components/pos-management/cart-content/no-select-order.tsx +26 -0
  118. package/src/components/pos-management/cart-content/order-info/customer-info.tsx +53 -0
  119. package/src/components/pos-management/cart-content/order-info/index.tsx +109 -0
  120. package/src/components/pos-management/cart-content/order-total.tsx +36 -0
  121. package/src/components/pos-management/cart-content/orders-line.tsx +72 -0
  122. package/src/components/pos-management/menu-content/category-tab.tsx +38 -0
  123. package/src/components/pos-management/menu-content/create-order-modal.tsx +65 -0
  124. package/src/components/pos-management/menu-content/product-content.tsx +93 -0
  125. package/src/components/pos-management/menu-content/product-detail/info.tsx +28 -0
  126. package/src/components/pos-management/menu-content/product-detail/modal.tsx +148 -0
  127. package/src/components/pos-management/menu-content/product-detail/option.tsx +87 -0
  128. package/src/components/pos-management/menu-content/product-detail/quantity-control.tsx +155 -0
  129. package/src/components/pos-management/menu-content/product-detail/sale-keypad.tsx +100 -0
  130. package/src/components/pos-management/menu-content/product-item.tsx +65 -0
  131. package/src/components/pos-management/order-helper/cancel-order-confirm.tsx +43 -0
  132. package/src/components/pos-management/order-helper/history-call.tsx +105 -0
  133. package/src/components/pos-management/order-helper/order-helper-modal.tsx +116 -0
  134. package/src/components/pos-management/payment-content/bill/actions.tsx +46 -0
  135. package/src/components/pos-management/payment-content/bill/content.tsx +207 -0
  136. package/src/components/pos-management/payment-content/bill/index.tsx +18 -0
  137. package/src/components/pos-management/payment-content/card-payment/index.tsx +124 -0
  138. package/src/components/pos-management/payment-content/card-payment/pos-payment/pos-connect.tsx +183 -0
  139. package/src/components/pos-management/payment-content/card-payment/pos-payment/qr-connect.tsx +185 -0
  140. package/src/components/pos-management/payment-content/card-payment/waiting-for-payment-pos-modal.tsx +37 -0
  141. package/src/components/pos-management/payment-content/cash-payment/index.tsx +216 -0
  142. package/src/components/pos-management/payment-content/index.tsx +70 -0
  143. package/src/components/pos-management/payment-content/payment-info.tsx +67 -0
  144. package/src/components/pos-management/payment-content/payment-layout.tsx +16 -0
  145. package/src/components/pos-management/payment-content/payment-method-cards.tsx +99 -0
  146. package/src/components/pos-management/payment-content/qr-payment/index.tsx +118 -0
  147. package/src/components/pos-management/payment-content/qr-payment/qr_code.js +29 -0
  148. package/src/components/pos-management/payment-content/qr-payment/vietqr.js +436 -0
  149. package/src/components/pos-management/payment-content/session-close-modal.tsx +35 -0
  150. package/src/components/pos-management/payment-content/soft-pos-payment/index.tsx +48 -0
  151. package/src/components/pos-management/pos-helpers/back-confirm.tsx +45 -0
  152. package/src/components/pos-management/pos-helpers/index.tsx +135 -0
  153. package/src/components/pos-management/pos-helpers/layout-display-modal.tsx +99 -0
  154. package/src/components/pos-management/search.tsx +48 -0
  155. package/src/components/pos-management/table-content/filtered-tables.tsx +59 -0
  156. package/src/components/pos-management/table-content/floor-tabs.tsx +65 -0
  157. package/src/components/pos-management/table-content/index.tsx +76 -0
  158. package/src/components/pos-management/table-content/table-item.tsx +127 -0
  159. package/src/components/pos-management/table-content/tables.tsx +96 -0
  160. package/src/components/restaurant-management/add-floor-modal.tsx +133 -0
  161. package/src/components/restaurant-management/add-table-modal.tsx +198 -0
  162. package/src/components/restaurant-management/delete-floor-confirm-modal.tsx +42 -0
  163. package/src/components/restaurant-management/delete-table-confirm-modal.tsx +51 -0
  164. package/src/components/restaurant-management/header.tsx +22 -0
  165. package/src/components/restaurant-management/index.tsx +54 -0
  166. package/src/components/restaurant-management/left-side.tsx +51 -0
  167. package/src/components/restaurant-management/right-side.tsx +179 -0
  168. package/src/components/restaurant-management/table-empty.tsx +43 -0
  169. package/src/components/session-management/close-session-modal/actions.tsx +45 -0
  170. package/src/components/session-management/close-session-modal/close-session-confirm.tsx +157 -0
  171. package/src/components/session-management/close-session-modal/close-session-ticket.tsx +218 -0
  172. package/src/components/session-management/close-session-modal/container.tsx +25 -0
  173. package/src/components/session-management/close-session-modal/draft-orders-confirm.tsx +53 -0
  174. package/src/components/session-management/close-session-modal/draft-orders-summary.tsx +82 -0
  175. package/src/components/session-management/close-session-modal/draft-orders.tsx +34 -0
  176. package/src/components/session-management/close-session-modal/index.tsx +35 -0
  177. package/src/components/session-management/close-session-modal/order/index.ts +1 -0
  178. package/src/components/session-management/close-session-modal/order/order-line.tsx +64 -0
  179. package/src/components/session-management/close-session-modal/order/orders-in-draft.tsx +31 -0
  180. package/src/components/session-management/close-session-modal/session-summary.tsx +165 -0
  181. package/src/components/session-management/index.ts +1 -0
  182. package/src/components/session-management/open-shift/index.tsx +172 -0
  183. package/src/components/table-management/index.tsx +0 -0
  184. package/src/constants/api/index.ts +1 -0
  185. package/src/constants/headers.constant.tsx +24 -0
  186. package/src/constants/index.ts +1 -0
  187. package/src/constants/language.store.ts +21 -0
  188. package/src/constants/methods.constant.ts +10 -0
  189. package/src/constants/order-state.ts +8 -0
  190. package/src/constants/payment-color.constant.ts +26 -0
  191. package/src/constants/query.constant.ts +14 -0
  192. package/src/constants/routes.constants.ts +23 -0
  193. package/src/constants/template-name.constant.ts +9 -0
  194. package/src/hooks/bill/use-get-bill-information.ts +49 -0
  195. package/src/hooks/bill/use-print-bill.tsx +0 -0
  196. package/src/hooks/common/load-env-config.ts +98 -0
  197. package/src/hooks/common/use-back.ts +13 -0
  198. package/src/hooks/common/use-broadcast.ts +22 -0
  199. package/src/hooks/common/use-click-outside.ts +58 -0
  200. package/src/hooks/common/use-get-base64-photo.ts +71 -0
  201. package/src/hooks/common/use-get-query.ts +25 -0
  202. package/src/hooks/common/use-pos.ts +21 -0
  203. package/src/hooks/common/use-query-params.ts +89 -0
  204. package/src/hooks/common/use-speech.ts +36 -0
  205. package/src/hooks/customer/use-customer-provider.ts +247 -0
  206. package/src/hooks/floor/use-floor-provider.ts +172 -0
  207. package/src/hooks/kitchen/use-kitchen-provider.ts +80 -0
  208. package/src/hooks/order/use-get-point-reward.ts +50 -0
  209. package/src/hooks/order/use-loop-fetch-order.ts +30 -0
  210. package/src/hooks/order/use-order-items.ts +61 -0
  211. package/src/hooks/order/use-orders.ts +76 -0
  212. package/src/hooks/payment/use-payment-provider.ts +221 -0
  213. package/src/hooks/product/use-product-provider.ts +87 -0
  214. package/src/hooks/session/use-check-session.tsx +19 -0
  215. package/src/hooks/session/use-session-provider.ts +79 -0
  216. package/src/hooks/table/use-pos-table-provider.ts +193 -0
  217. package/src/index.css +5 -0
  218. package/src/index.ts +10 -0
  219. package/src/layouts/common.tsx +15 -0
  220. package/src/layouts/index.ts +4 -0
  221. package/src/layouts/pos-layout.tsx +33 -0
  222. package/src/layouts/pos-order-layout.tsx +43 -0
  223. package/src/layouts/sale-layout.tsx +25 -0
  224. package/src/locales/en.json +394 -0
  225. package/src/locales/vi.json +400 -0
  226. package/src/pages/index.ts +4 -0
  227. package/src/pages/login/index.tsx +128 -0
  228. package/src/pages/pincode/index.tsx +198 -0
  229. package/src/pages/pos/kitchen-management/layout.tsx +18 -0
  230. package/src/pages/pos/management-floor/index.tsx +7 -0
  231. package/src/pages/pos/management-order/index.tsx +7 -0
  232. package/src/pages/pos/management-order/order-detail/index.tsx +7 -0
  233. package/src/pages/pos/management-table/index.tsx +0 -0
  234. package/src/pages/pos/payment-success/index.tsx +75 -0
  235. package/src/provider/app-provider.tsx +56 -0
  236. package/src/provider/fallback/custom-error.tsx +26 -0
  237. package/src/provider/main-provider.tsx +41 -0
  238. package/src/provider/meta-provider.tsx +72 -0
  239. package/src/provider/modal-provider.tsx +48 -0
  240. package/src/provider/notification-provider.tsx +64 -0
  241. package/src/provider/pos-provider/close-session-provider/index.tsx +207 -0
  242. package/src/provider/pos-provider/customer-provider/index.tsx +30 -0
  243. package/src/provider/pos-provider/floor-provider/index.tsx +39 -0
  244. package/src/provider/pos-provider/index.ts +6 -0
  245. package/src/provider/pos-provider/kitchen-provider/index.tsx +30 -0
  246. package/src/provider/pos-provider/order-detail-provider/index.tsx +233 -0
  247. package/src/provider/pos-provider/order-provider/index.tsx +803 -0
  248. package/src/provider/pos-provider/payment-provider/index.tsx +30 -0
  249. package/src/provider/pos-provider/product-provider/index.tsx +30 -0
  250. package/src/provider/pos-provider/sale-provider/index.tsx +168 -0
  251. package/src/provider/pos-provider/session-provider/index.tsx +30 -0
  252. package/src/provider/pos-provider/socket-provider/index.tsx +118 -0
  253. package/src/provider/pos-provider/table-provider/index.tsx +30 -0
  254. package/src/provider/public-provider.tsx +104 -0
  255. package/src/provider/use-session-provider.ts +79 -0
  256. package/src/router/app-router.tsx +38 -0
  257. package/src/router/index.tsx +26 -0
  258. package/src/router/pos-route.tsx +75 -0
  259. package/src/router/protected-route.tsx +16 -0
  260. package/src/router/public-route.tsx +11 -0
  261. package/src/store/header/index.ts +21 -0
  262. package/src/store/session/index.ts +25 -0
  263. package/src/store/states/cart.state.ts +135 -0
  264. package/src/store/states/close-session.state.ts +20 -0
  265. package/src/store/states/customer.state.ts +19 -0
  266. package/src/store/states/payment.state.ts +14 -0
  267. package/src/styles/base.css +212 -0
  268. package/src/styles/common.css +65 -0
  269. package/src/styles/lib/tailwind.css +0 -0
  270. package/src/styles/lib/tailwind.theme.css +34 -0
  271. package/src/styles/loading.css +72 -0
  272. package/src/styles/main.css +5 -0
  273. package/src/styles/refreshing-content.css +55 -0
  274. package/src/styles/text.css +44 -0
  275. package/src/types/account.ts +61 -0
  276. package/src/types/branch.ts +6 -0
  277. package/src/types/category.ts +13 -0
  278. package/src/types/common.ts +4 -0
  279. package/src/types/customer.ts +52 -0
  280. package/src/types/dashboard.ts +18 -0
  281. package/src/types/edc.ts +37 -0
  282. package/src/types/export-e-invoice.ts +17 -0
  283. package/src/types/filter.d.ts +12 -0
  284. package/src/types/floor/floor.ts +16 -0
  285. package/src/types/floor.d.ts +36 -0
  286. package/src/types/index.ts +127 -0
  287. package/src/types/invoice.ts +32 -0
  288. package/src/types/modal.ts +15 -0
  289. package/src/types/notification.ts +12 -0
  290. package/src/types/order.ts +182 -0
  291. package/src/types/payment.ts +44 -0
  292. package/src/types/product/product.ts +47 -0
  293. package/src/types/product.ts +137 -0
  294. package/src/types/provider-info.d.ts +14 -0
  295. package/src/types/qr.d.ts +25 -0
  296. package/src/types/report.d.ts +43 -0
  297. package/src/types/sale.d.ts +68 -0
  298. package/src/types/search.d.ts +7 -0
  299. package/src/types/session.d.ts +30 -0
  300. package/src/types/shop-qr.d.ts +89 -0
  301. package/src/types/staff.d.ts +35 -0
  302. package/src/types/store.d.ts +25 -0
  303. package/src/types/table.d.ts +57 -0
  304. package/src/utils/close-session-ticket.tsx +129 -0
  305. package/src/utils/functions.ts +299 -0
  306. package/src/utils/i18n.ts +25 -0
  307. package/src/utils/pos/bill.ts +156 -0
  308. package/src/utils/pos/convert-order.ts +58 -0
  309. package/src/utils/pos/helpers.ts +48 -0
  310. package/src/utils/pos/session.ts +44 -0
  311. package/src/utils/storages/index.ts +1 -0
  312. package/src/utils/storages/local-storage.ts +72 -0
  313. package/tailwind.preset.ts +25 -0
  314. package/tsconfig.json +30 -0
  315. package/tsup.config.ts +30 -0
  316. package/dist/index.d.ts +0 -58
  317. package/dist/index.js +0 -145
  318. package/dist/index.js.map +0 -1
@@ -0,0 +1,96 @@
1
+ import { EmptyState } from "@components/common/empty-state";
2
+ import { usePosTable } from "@provider/pos-provider/table-provider";
3
+ import { useMemo, useState } from "react";
4
+ import { useTranslation } from "react-i18next";
5
+ import { TableItem } from "./table-item";
6
+
7
+ type TProps = {
8
+ onOpenAddModal: () => void;
9
+ };
10
+ const tableType = [
11
+ {
12
+ id: 1,
13
+ name: "Tất cả",
14
+ value: "all",
15
+ },
16
+ {
17
+ id: 2,
18
+ name: "Trống",
19
+ value: "available",
20
+ },
21
+ {
22
+ id: 3,
23
+ name: "Đang sử dụng",
24
+ value: "unavailable",
25
+ },
26
+ ];
27
+ const Tables = ({ onOpenAddModal }: TProps) => {
28
+ const { t } = useTranslation();
29
+ const { mapTablesWithOrder } = usePosTable();
30
+ const [type, setType] = useState(tableType[0].value);
31
+
32
+ const getFilterTable = (value: string) => {
33
+ switch (value) {
34
+ case "all":
35
+ return mapTablesWithOrder;
36
+ case "available":
37
+ return mapTablesWithOrder.filter(
38
+ (table) => !table.currentOrder && !table.isTakeAway
39
+ );
40
+ case "unavailable":
41
+ return mapTablesWithOrder.filter(
42
+ (table) => !!table.currentOrder && !table.isTakeAway
43
+ );
44
+ }
45
+ };
46
+
47
+ const filteredByTypeTables = useMemo(() => {
48
+ return getFilterTable(type);
49
+ }, [mapTablesWithOrder, type]);
50
+
51
+ return (
52
+ <div className="flex flex-col py-4 flex-1 overflow-y-auto border-t border-stroke-default">
53
+ <div className="flex gap-3 justify-center">
54
+ {tableType.map((table) => {
55
+ const isActive = type === table.value;
56
+ const size = getFilterTable(table.value)?.length ?? 0;
57
+ return (
58
+ <div
59
+ key={table.id}
60
+ onClick={() => setType(table.value)}
61
+ className={`h-11 px-3 flex justify-center items-center rounded-full cursor-pointer ${
62
+ isActive
63
+ ? "border-primary text-primary border-[2px]"
64
+ : "border-stroke-disabled text-text-primary border"
65
+ }`}
66
+ >
67
+ {table.name} ({size})
68
+ </div>
69
+ );
70
+ })}
71
+ </div>
72
+ <div className="z-0 w-full overflow-y-auto flex-1 p-4">
73
+ {filteredByTypeTables && filteredByTypeTables.length > 0 ? (
74
+ <div className="grid gap-5 grid-cols-[repeat(auto-fill,minmax(157px,1fr))]">
75
+ {filteredByTypeTables.map((table) => (
76
+ <TableItem key={table.table.id} tableCard={table} />
77
+ ))}
78
+ </div>
79
+ ) : (
80
+ <div className="z-0">
81
+ <EmptyState
82
+ image="/assets/images/empty-table-state.png"
83
+ imageAlt={t("no_table")}
84
+ title={t("no_table")}
85
+ description={t("try_add_table")}
86
+ buttonLabel={t("create_table")}
87
+ onAction={onOpenAddModal}
88
+ />
89
+ </div>
90
+ )}
91
+ </div>
92
+ </div>
93
+ );
94
+ };
95
+
96
+ export default Tables;
@@ -0,0 +1,133 @@
1
+ import { IcPlus } from "@assets/icons/common";
2
+ import ButtonAction from "@components/common/button-action";
3
+ import Input from "@components/common/input";
4
+ import ModalZoom from "@components/common/modal/modal-zoom";
5
+ import { zodResolver } from "@hookform/resolvers/zod";
6
+ import { useFloor } from "@provider/pos-provider/floor-provider";
7
+ import { useEffect, useMemo, useState } from "react";
8
+ import { useForm } from "react-hook-form";
9
+ import { useTranslation } from "react-i18next";
10
+ import z from "zod";
11
+
12
+ type TProps = {
13
+ defaultName?: string;
14
+ editingFloor?: number;
15
+ setIsEditingFloor?: (val: number | undefined) => void;
16
+ isOpen: boolean;
17
+ onClose: () => void;
18
+ };
19
+
20
+ export const AddFloorModal = ({
21
+ defaultName,
22
+ editingFloor,
23
+ setIsEditingFloor,
24
+ isOpen,
25
+ onClose,
26
+ }: TProps) => {
27
+ const [isLoading, setIsLoading] = useState(false);
28
+ const { floors, onCreateFloor, onUpdateFloor } = useFloor();
29
+ const { t } = useTranslation();
30
+
31
+ const matchedFloor = useMemo(() => {
32
+ return floors.find((floor) => floor.id === editingFloor);
33
+ }, [floors]);
34
+
35
+ const {
36
+ handleSubmit,
37
+ register,
38
+ setValue,
39
+ formState: { errors },
40
+ setError,
41
+ } = useForm({
42
+ defaultValues: {
43
+ name: defaultName || "",
44
+ },
45
+ mode: "onChange",
46
+ resolver: zodResolver(
47
+ z.object({
48
+ name: z.string().min(1, "Tên tầng là bắt buộc"), //TODO
49
+ })
50
+ ),
51
+ });
52
+
53
+ const onSubmit = handleSubmit((data) => {
54
+ try {
55
+ setIsLoading(true);
56
+ if (editingFloor) handleEditFloorSubmit(data.name);
57
+ else handleAddFloorSubmit(data.name);
58
+ } catch (error: any) {
59
+ setError("name", { message: error?.message || "Lỗi không xác định" }); //TODO
60
+ setIsLoading(false);
61
+ console.error("Create floor error:", error);
62
+ } finally {
63
+ setIsLoading(false);
64
+ }
65
+ });
66
+
67
+ const handleAddFloorSubmit = async (name: string) => {
68
+ await onCreateFloor(name, () => {
69
+ setValue("name", "");
70
+ onClose();
71
+ });
72
+ };
73
+
74
+ const handleEditFloorSubmit = async (name: string) => {
75
+ if (!editingFloor) return;
76
+ await onUpdateFloor(Number(editingFloor), name, () => {
77
+ setValue("name", "");
78
+ onClose();
79
+ setIsEditingFloor && setIsEditingFloor(undefined);
80
+ });
81
+ };
82
+
83
+ const handleClose = () => {
84
+ setValue("name", "");
85
+ setError("name", { message: "" });
86
+ onClose();
87
+ setIsEditingFloor && setIsEditingFloor(undefined);
88
+ };
89
+
90
+ useEffect(() => {
91
+ if (editingFloor) setValue("name", matchedFloor?.name || "");
92
+ }, [editingFloor]);
93
+
94
+ return (
95
+ <ModalZoom
96
+ isOpen={isOpen}
97
+ onClose={handleClose}
98
+ title={editingFloor ? t("edit_floor") : t("add_floor")}
99
+ className="p-6 rounded-2xl bg-white w-[472px]"
100
+ >
101
+ <form onSubmit={onSubmit} className="flex flex-col gap-6">
102
+ <Input
103
+ title={t("floor_name")}
104
+ register={register("name")}
105
+ errorMessage={errors.name?.message}
106
+ isRequired
107
+ inputClassName="p-3"
108
+ placeholder="Nhập tên tầng" //TODO
109
+ />
110
+
111
+ <div className="flex gap-2 w-full">
112
+ <ButtonAction
113
+ text={t("cancel_button")}
114
+ className="button-secondary w-full h-[60px]"
115
+ onClick={handleClose}
116
+ />
117
+ <ButtonAction
118
+ type="submit"
119
+ text={
120
+ isLoading
121
+ ? t("loading")
122
+ : editingFloor
123
+ ? t("edit_floor")
124
+ : t("add_floor_btn_label")
125
+ }
126
+ className="button-primary w-full h-[60px]"
127
+ iconSrc={isLoading || editingFloor ? "" : <IcPlus />}
128
+ />
129
+ </div>
130
+ </form>
131
+ </ModalZoom>
132
+ );
133
+ };
@@ -0,0 +1,198 @@
1
+ import { IcPlus, IcTrash } from "@assets/icons/common";
2
+ import ButtonAction from "@components/common/button-action";
3
+ import Input from "@components/common/input";
4
+ import ModalZoom from "@components/common/modal/modal-zoom";
5
+ import { zodResolver } from "@hookform/resolvers/zod";
6
+ import useGetQuery from "@hooks/common/use-get-query";
7
+ import { usePosTable } from "@provider/pos-provider/table-provider";
8
+ import { TBasicTable } from "@type/table";
9
+ import { useEffect, useMemo, useState } from "react";
10
+ import { useForm } from "react-hook-form";
11
+ import { useTranslation } from "react-i18next";
12
+ import { toast } from "react-toastify";
13
+ import z from "zod";
14
+
15
+ const schema = z.object({
16
+ tableNumber: z.coerce.number("Vui lòng nhập số").min(1, "Số bàn là bắt buộc"),
17
+ seats: z.coerce.number("Vui lòng nhập số").min(1, "Sức chứa là bắt buộc"),
18
+ });
19
+
20
+ type TProps = {
21
+ isOpen: boolean;
22
+ onClose: () => void;
23
+ editMode?: boolean;
24
+ tableSelected?: TBasicTable;
25
+ onOpenDeleteConfirmModal?: () => void;
26
+ onTableSelected?: (table: TBasicTable | undefined) => void;
27
+ };
28
+
29
+ export const AddTableModal = ({
30
+ isOpen,
31
+ onClose,
32
+ editMode,
33
+ tableSelected,
34
+ onOpenDeleteConfirmModal,
35
+ onTableSelected,
36
+ }: TProps) => {
37
+ const { t } = useTranslation();
38
+ const {
39
+ onCreateTable,
40
+ tablesByFloor: tableData,
41
+ onUpdateTable,
42
+ mapTablesWithOrder,
43
+ } = usePosTable();
44
+ const { floorId } = useGetQuery();
45
+ const [loading, setLoading] = useState(false);
46
+
47
+ const {
48
+ register,
49
+ formState: { errors },
50
+ handleSubmit,
51
+ setValue,
52
+ setError,
53
+ } = useForm({
54
+ defaultValues: {
55
+ tableNumber: "",
56
+ seats: "",
57
+ },
58
+ mode: "onChange",
59
+ resolver: zodResolver(schema),
60
+ });
61
+
62
+ const onSubmit = handleSubmit(async (data) => {
63
+ const payload = {
64
+ tableNumber: data.tableNumber,
65
+ seats: Number(data.seats),
66
+ };
67
+
68
+ const isExist = tableData?.some(
69
+ (table: TBasicTable) =>
70
+ table.table_number === Number(payload.tableNumber) &&
71
+ table.table_number !== tableSelected?.table_number
72
+ );
73
+
74
+ if (isExist) {
75
+ toast.error("Bàn đã tồn tại"); //TODO
76
+ return;
77
+ }
78
+
79
+ setLoading(true);
80
+
81
+ try {
82
+ if (editMode) {
83
+ onUpdateTable({
84
+ tableId: tableSelected?.id || 0,
85
+ tableNumber: String(payload.tableNumber),
86
+ seats: payload.seats,
87
+ });
88
+ } else {
89
+ onCreateTable({
90
+ tableNumber: payload.tableNumber,
91
+ seats: payload.seats,
92
+ floorId: Number(floorId),
93
+ });
94
+ }
95
+ } catch (error: any) {
96
+ toast.error(error?.message);
97
+ } finally {
98
+ handleClose();
99
+ onTableSelected?.(undefined);
100
+ setLoading(false);
101
+ }
102
+ });
103
+
104
+ const handleClose = () => {
105
+ setValue("tableNumber", "");
106
+ setValue("seats", "");
107
+ setError("tableNumber", { message: "" });
108
+ setError("seats", { message: "" });
109
+ onClose();
110
+ };
111
+
112
+ const isTableContainOrder = useMemo(() => {
113
+ return mapTablesWithOrder.find(
114
+ (table) => table.table.id === tableSelected?.id
115
+ )?.currentOrder;
116
+ }, [tableSelected]);
117
+
118
+ const handleDeleteTable = () => {
119
+ if (isTableContainOrder) {
120
+ toast.error("Bàn đang có đơn hàng");
121
+ } else {
122
+ onOpenDeleteConfirmModal?.();
123
+ handleClose();
124
+ }
125
+ };
126
+
127
+ useEffect(() => {
128
+ if (tableSelected) {
129
+ setValue("tableNumber", tableSelected.table_number);
130
+ setValue("seats", tableSelected.seats);
131
+ }
132
+ }, [tableSelected]);
133
+
134
+ return (
135
+ <ModalZoom
136
+ isOpen={isOpen}
137
+ onClose={handleClose}
138
+ title={editMode ? t("edit_table") : t("add_new_table")}
139
+ className="p-6 rounded-2xl bg-white"
140
+ headerAction={
141
+ editMode && (
142
+ <button onClick={handleDeleteTable} className="text-state-error-base">
143
+ <IcTrash />
144
+ </button>
145
+ )
146
+ }
147
+ >
148
+ <form onSubmit={onSubmit} className="flex flex-col gap-6">
149
+ <div className="flex items-center justify-center gap-6 w-full">
150
+ <Input
151
+ title="Số bàn" //TODO
152
+ register={register("tableNumber")}
153
+ placeholder="Nhập tên bàn" //TODO
154
+ isRequired
155
+ inputMode="numeric"
156
+ type="number"
157
+ errorMessage={errors.tableNumber?.message}
158
+ className="flex-1"
159
+ inputClassName="py-[15px] px-3"
160
+ />
161
+
162
+ <Input
163
+ title="Sức chứa" //TODO
164
+ register={register("seats")}
165
+ placeholder="Nhập sức chứa" //TODO
166
+ isRequired
167
+ inputMode="numeric"
168
+ type="number"
169
+ errorMessage={errors.seats?.message}
170
+ className="flex-1"
171
+ inputClassName="py-[15px] px-3"
172
+ />
173
+ </div>
174
+
175
+ <div className="flex gap-2 w-full">
176
+ <ButtonAction
177
+ text={t("cancel_button")}
178
+ className="button-secondary w-full h-[60px]"
179
+ onClick={handleClose}
180
+ />
181
+ <ButtonAction
182
+ type="submit"
183
+ disabled={loading}
184
+ text={
185
+ loading
186
+ ? t("loading")
187
+ : editMode
188
+ ? t("update_button")
189
+ : t("add_table")
190
+ }
191
+ className="button-primary w-full h-[60px]"
192
+ iconSrc={loading || editMode ? "" : <IcPlus />}
193
+ />
194
+ </div>
195
+ </form>
196
+ </ModalZoom>
197
+ );
198
+ };
@@ -0,0 +1,42 @@
1
+ import DeleteConfirmModalContainer from "@components/common/modal/delete-confirm-modal-container";
2
+ import { useFloor } from "@provider/pos-provider/floor-provider";
3
+ import { Trans, useTranslation } from "react-i18next";
4
+
5
+ const DeleteFloorConfirmModal = ({
6
+ isOpen,
7
+ onClose,
8
+ floorId,
9
+ floorName,
10
+ }: {
11
+ isOpen: boolean;
12
+ onClose: () => void;
13
+ floorId: number;
14
+ floorName: string;
15
+ }) => {
16
+ const { t } = useTranslation();
17
+ const { onDeleteFloor } = useFloor();
18
+
19
+ const deleteFloor = async () => {
20
+ await onDeleteFloor(floorId, () => {
21
+ onClose();
22
+ });
23
+ };
24
+
25
+ return (
26
+ <DeleteConfirmModalContainer
27
+ title={t("confirm_delete_floor")}
28
+ description={
29
+ <Trans
30
+ i18nKey="confirm_delete_table"
31
+ values={{ floorName }}
32
+ components={{ bold: <span className="text-text-primary" /> }}
33
+ />
34
+ }
35
+ onAction={deleteFloor}
36
+ onClose={onClose}
37
+ isOpen={isOpen}
38
+ />
39
+ );
40
+ };
41
+
42
+ export default DeleteFloorConfirmModal;
@@ -0,0 +1,51 @@
1
+ import DeleteConfirmModalContainer from "@components/common/modal/delete-confirm-modal-container";
2
+ import { usePosTable } from "@provider/pos-provider/table-provider";
3
+ import { TBasicTable } from "@type/table";
4
+ import { Trans, useTranslation } from "react-i18next";
5
+ import { toast } from "react-toastify";
6
+
7
+ type TProps = {
8
+ isOpen: boolean;
9
+ onClose: () => void;
10
+ tableSelected?: TBasicTable;
11
+ };
12
+
13
+ const DeleteTableConfirmModal = ({
14
+ isOpen,
15
+ onClose,
16
+ tableSelected,
17
+ }: TProps) => {
18
+ const { t } = useTranslation();
19
+ const { onDeleteTable: deleteTable } = usePosTable();
20
+
21
+ const onDeleteTable = async () => {
22
+ try {
23
+ if (!tableSelected) return;
24
+ deleteTable(tableSelected?.id, () => {
25
+ onClose();
26
+ });
27
+ } catch (error: any) {
28
+ toast.error(error);
29
+ }
30
+ };
31
+
32
+ return (
33
+ <DeleteConfirmModalContainer
34
+ title={t("confirm_delete_table_title")}
35
+ description={
36
+ <Trans
37
+ i18nKey="confirm_delete_table_description"
38
+ values={{ tableName: tableSelected?.table_number }}
39
+ components={{
40
+ bold: <span className="text-text-primary font-semibold" />,
41
+ }}
42
+ />
43
+ }
44
+ onAction={onDeleteTable}
45
+ onClose={onClose}
46
+ isOpen={isOpen}
47
+ />
48
+ );
49
+ };
50
+
51
+ export default DeleteTableConfirmModal;
@@ -0,0 +1,22 @@
1
+ import { useTranslation } from "react-i18next"
2
+ import { useNavigate } from "react-router-dom"
3
+
4
+ export const Header = () => {
5
+ const { t } = useTranslation()
6
+ const navigate = useNavigate()
7
+
8
+ return (
9
+ <div className="flex items-center justify-between h-[60px] px-3 py-[6px] border-b-[0.5px] bg-white">
10
+ <button
11
+ onClick={() => navigate(-1)}
12
+ className="w-12 aspect-square bg-neutral-disabled rounded-lg"
13
+ >
14
+
15
+ </button>
16
+ <p className="text-lg text-strong-950 font-semibold leading-[26px]">
17
+ {t("floor-management")}
18
+ </p>
19
+ <div />
20
+ </div>
21
+ )
22
+ }
@@ -0,0 +1,54 @@
1
+ import useGetQuery from "@hooks/common/use-get-query";
2
+ import { useFloor } from "@provider/pos-provider/floor-provider";
3
+ import { useMemo, useState } from "react";
4
+ import { AddFloorModal } from "./add-floor-modal";
5
+ import { Header } from "./header";
6
+ import LeftSide from "./left-side";
7
+ import RightSide from "./right-side";
8
+
9
+ const ManagementFloor = () => {
10
+ const { floors } = useFloor();
11
+ const { floorId } = useGetQuery();
12
+ const [isOpenAddFloor, setIsOpenAddFloor] = useState(false);
13
+ const [isEditingFloor, setIsEditingFloor] = useState<number | undefined>();
14
+
15
+ const activeFloor = useMemo(() => {
16
+ if (!floors.length) return;
17
+
18
+ if (!floorId) floors[0]?.id;
19
+
20
+ const activeFloor = floors.find((floor) => floor.id === floorId);
21
+
22
+ return activeFloor ?? floors[0];
23
+ }, [floors, floorId]);
24
+
25
+ return (
26
+ <div className="flex flex-col h-screen">
27
+ <Header />
28
+ <div className="flex flex-1 overflow-auto ">
29
+ <LeftSide
30
+ floors={floors}
31
+ activeFloor={activeFloor}
32
+ isOpenAddFloor={isOpenAddFloor}
33
+ setIsOpenAddFloor={setIsOpenAddFloor}
34
+ />
35
+
36
+ <RightSide
37
+ activeFloor={activeFloor}
38
+ isOpenAddFloor={isOpenAddFloor}
39
+ setIsOpenAddFloor={setIsOpenAddFloor}
40
+ setIsEditingFloor={setIsEditingFloor}
41
+ />
42
+
43
+ <AddFloorModal
44
+ isOpen={isOpenAddFloor}
45
+ editingFloor={isEditingFloor}
46
+ onClose={() => setIsOpenAddFloor(false)}
47
+ setIsEditingFloor={setIsEditingFloor}
48
+ />
49
+ </div>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default ManagementFloor;
@@ -0,0 +1,51 @@
1
+ import { IcPlus } from "@assets/icons/common";
2
+ import ButtonAction from "@components/common/button-action";
3
+ import { QUERY_KEYS } from "@constants/query.constant";
4
+ import { useQueryParams } from "@hooks/common/use-query-params";
5
+ import { TFloor } from "@type/floor/floor";
6
+ import { cn } from "@utils/functions";
7
+
8
+ type TProps = {
9
+ floors: TFloor[];
10
+ activeFloor: TFloor | undefined;
11
+ setIsOpenAddFloor: (isOpen: boolean) => void;
12
+ isOpenAddFloor: boolean;
13
+ };
14
+
15
+ const LeftSide = ({ floors, activeFloor, setIsOpenAddFloor }: TProps) => {
16
+ const { updateQuery } = useQueryParams();
17
+
18
+ const handleUpdateFloor = (floorId: string) => {
19
+ updateQuery(QUERY_KEYS.FLOOR, floorId);
20
+ };
21
+ return (
22
+ <div className="w-fit h-full flex flex-col gap-4 p-2 border-r-[0.5px] border-stroke-disabled bg-white">
23
+ <div className="flex-1 flex flex-col overflow-y-auto hide-scrollbar w-full">
24
+ {floors.map((floor) => (
25
+ <div
26
+ key={floor.id}
27
+ onClick={() => handleUpdateFloor(floor.id.toString())}
28
+ className={cn(
29
+ "p-3 text-text-disable font-medium text-sm leading-5 tracking-[-0.12px] h-fit min-h-12 rounded-lg w-full flex items-center cursor-pointer",
30
+ {
31
+ "bg-surface-primary text-text-active font-semibold":
32
+ activeFloor?.id === floor.id,
33
+ }
34
+ )}
35
+ >
36
+ {floor.name}
37
+ </div>
38
+ ))}
39
+ </div>
40
+
41
+ <ButtonAction
42
+ className="button-primary px-3 min-w-fit w-fit"
43
+ text=" Tạo tầng"
44
+ iconSrc={<IcPlus />}
45
+ onClick={() => setIsOpenAddFloor(true)}
46
+ />
47
+ </div>
48
+ );
49
+ };
50
+
51
+ export default LeftSide;