Browse Source

Refactor order status handling and improve product detail options

Centralized order status text and color logic in loigicUtils and updated usage in OrderDetailView and OrderHistoryView. Enhanced ProductDetailView to use package titles for data options, improving flexibility and display. Minor code cleanups and UI improvements included.
trunghieubui 2 weeks ago
parent
commit
771b2d52b4

+ 25 - 4
EsimLao/docs/skyhub.drawio

@@ -1,6 +1,6 @@
-<mxfile host="Electron" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.3.0 Chrome/140.0.7339.249 Electron/38.7.2 Safari/537.36" version="29.3.0">
+<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.3.0 Chrome/140.0.7339.249 Electron/38.7.2 Safari/537.36" version="29.3.0">
   <diagram id="kgpKYQtTHZ0yAKxKKP6v" name="Page-1">
   <diagram id="kgpKYQtTHZ0yAKxKKP6v" name="Page-1">
-    <mxGraphModel dx="2483" dy="2183" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
+    <mxGraphModel dx="2511" dy="2073" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
       <root>
       <root>
         <mxCell id="0" />
         <mxCell id="0" />
         <mxCell id="1" parent="0" />
         <mxCell id="1" parent="0" />
@@ -130,10 +130,10 @@
         <mxCell id="uRcrelpJeVWRNYr8ECgl-48" parent="1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.worker;fillColor=#D9A741;gradientColor=none;" value="PORTAL" vertex="1">
         <mxCell id="uRcrelpJeVWRNYr8ECgl-48" parent="1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.worker;fillColor=#D9A741;gradientColor=none;" value="PORTAL" vertex="1">
           <mxGeometry height="63" width="60" x="595" y="430" as="geometry" />
           <mxGeometry height="63" width="60" x="595" y="430" as="geometry" />
         </mxCell>
         </mxCell>
-        <mxCell id="uRcrelpJeVWRNYr8ECgl-49" parent="1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.worker;fillColor=#D9A741;gradientColor=none;" value="B2C APIS" vertex="1">
+        <mxCell id="uRcrelpJeVWRNYr8ECgl-49" parent="1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.worker;fillColor=#D9A741;gradientColor=none;" value="CUSTOMER" vertex="1">
           <mxGeometry height="63" width="60" x="720" y="327" as="geometry" />
           <mxGeometry height="63" width="60" x="720" y="327" as="geometry" />
         </mxCell>
         </mxCell>
-        <mxCell id="uRcrelpJeVWRNYr8ECgl-50" parent="1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.worker;fillColor=#D9A741;gradientColor=none;" value="B2B APIS" vertex="1">
+        <mxCell id="uRcrelpJeVWRNYr8ECgl-50" parent="1" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.worker;fillColor=#D9A741;gradientColor=none;" value="CO&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;MISSION&lt;/span&gt;" vertex="1">
           <mxGeometry height="63" width="60" x="720" y="430" as="geometry" />
           <mxGeometry height="63" width="60" x="720" y="430" as="geometry" />
         </mxCell>
         </mxCell>
         <mxCell id="uRcrelpJeVWRNYr8ECgl-52" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="&lt;font style=&quot;font-size: 18px;&quot;&gt;CORE&lt;/font&gt;" vertex="1">
         <mxCell id="uRcrelpJeVWRNYr8ECgl-52" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="&lt;font style=&quot;font-size: 18px;&quot;&gt;CORE&lt;/font&gt;" vertex="1">
@@ -270,6 +270,27 @@
         <mxCell id="uRcrelpJeVWRNYr8ECgl-104" parent="1" style="text;html=1;whiteSpace=wrap;overflow=hidden;rounded=0;" value="&lt;h1 style=&quot;margin-top: 0px;&quot;&gt;Công nghệ sử dụng&lt;/h1&gt;&lt;div&gt;Front end:&lt;/div&gt;&lt;div&gt;+ Website/MiniApp: ReactJS vite tool&lt;/div&gt;&lt;div&gt;+ Application: Flutter&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Backend:&lt;/div&gt;&lt;div&gt;+ 100% sử dụng Dotnet core 7 API&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Database:&lt;/div&gt;&lt;div&gt;+ Oracle&lt;/div&gt;&lt;div&gt;+ PostgresSQL&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Cache:&lt;/div&gt;&lt;div&gt;+ Redis&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Queue:&lt;/div&gt;&lt;div&gt;+ Kafka&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Identify service:&lt;/div&gt;&lt;div&gt;+ Keycloak&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Api Gateway:&lt;/div&gt;&lt;div&gt;+ KONG&amp;nbsp;&lt;/div&gt;" vertex="1">
         <mxCell id="uRcrelpJeVWRNYr8ECgl-104" parent="1" style="text;html=1;whiteSpace=wrap;overflow=hidden;rounded=0;" value="&lt;h1 style=&quot;margin-top: 0px;&quot;&gt;Công nghệ sử dụng&lt;/h1&gt;&lt;div&gt;Front end:&lt;/div&gt;&lt;div&gt;+ Website/MiniApp: ReactJS vite tool&lt;/div&gt;&lt;div&gt;+ Application: Flutter&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Backend:&lt;/div&gt;&lt;div&gt;+ 100% sử dụng Dotnet core 7 API&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Database:&lt;/div&gt;&lt;div&gt;+ Oracle&lt;/div&gt;&lt;div&gt;+ PostgresSQL&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Cache:&lt;/div&gt;&lt;div&gt;+ Redis&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Queue:&lt;/div&gt;&lt;div&gt;+ Kafka&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Identify service:&lt;/div&gt;&lt;div&gt;+ Keycloak&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Api Gateway:&lt;/div&gt;&lt;div&gt;+ KONG&amp;nbsp;&lt;/div&gt;" vertex="1">
           <mxGeometry height="380" width="490" x="1030" y="-329" as="geometry" />
           <mxGeometry height="380" width="490" x="1030" y="-329" as="geometry" />
         </mxCell>
         </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-8" parent="1" style="shape=umlLifeline;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;dropTarget=0;collapsible=0;recursiveResize=0;outlineConnect=0;portConstraint=eastwest;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;elbow&quot;:&quot;vertical&quot;,&quot;curved&quot;:0,&quot;rounded&quot;:0};" value="Customer" vertex="1">
+          <mxGeometry height="510" width="100" x="2130" y="-560" as="geometry" />
+        </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-9" parent="8LnyclVRHVrttfvcOQKk-8" style="html=1;points=[[0,0,0,0,5],[0,1,0,0,-5],[1,0,0,0,5],[1,1,0,0,-5]];perimeter=orthogonalPerimeter;outlineConnect=0;targetShapes=umlLifeline;portConstraint=eastwest;newEdgeStyle={&quot;curved&quot;:0,&quot;rounded&quot;:0};fillColor=#808080;" value="" vertex="1">
+          <mxGeometry height="120" width="10" x="45" y="90" as="geometry" />
+        </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-10" parent="1" style="shape=umlLifeline;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;dropTarget=0;collapsible=0;recursiveResize=0;outlineConnect=0;portConstraint=eastwest;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;elbow&quot;:&quot;vertical&quot;,&quot;curved&quot;:0,&quot;rounded&quot;:0};" value="ESIM" vertex="1">
+          <mxGeometry height="520" width="100" x="1910" y="-560" as="geometry" />
+        </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-11" parent="8LnyclVRHVrttfvcOQKk-10" style="html=1;points=[[0,0,0,0,5],[0,1,0,0,-5],[1,0,0,0,5],[1,1,0,0,-5]];perimeter=orthogonalPerimeter;outlineConnect=0;targetShapes=umlLifeline;portConstraint=eastwest;newEdgeStyle={&quot;curved&quot;:0,&quot;rounded&quot;:0};" value="" vertex="1">
+          <mxGeometry height="120" width="10" x="45" y="130" as="geometry" />
+        </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-19" parent="1" style="shape=umlLifeline;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;dropTarget=0;collapsible=0;recursiveResize=0;outlineConnect=0;portConstraint=eastwest;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;elbow&quot;:&quot;vertical&quot;,&quot;curved&quot;:0,&quot;rounded&quot;:0};" value="Mini APP" vertex="1">
+          <mxGeometry height="520" width="100" x="1700" y="-560" as="geometry" />
+        </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-20" parent="8LnyclVRHVrttfvcOQKk-19" style="html=1;points=[[0,0,0,0,5],[0,1,0,0,-5],[1,0,0,0,5],[1,1,0,0,-5]];perimeter=orthogonalPerimeter;outlineConnect=0;targetShapes=umlLifeline;portConstraint=eastwest;newEdgeStyle={&quot;curved&quot;:0,&quot;rounded&quot;:0};" value="" vertex="1">
+          <mxGeometry height="120" width="10" x="45" y="130" as="geometry" />
+        </mxCell>
+        <mxCell id="8LnyclVRHVrttfvcOQKk-23" parent="1" style="verticalAlign=top;align=left;overflow=fill;html=1;whiteSpace=wrap;" value="&lt;p style=&quot;margin:0px;margin-top:4px;text-align:center;text-decoration:underline;&quot;&gt;&lt;b&gt;Login&lt;/b&gt;&lt;/p&gt;&lt;hr size=&quot;1&quot; style=&quot;border-style:solid;&quot;&gt;&lt;p style=&quot;margin:0px;margin-left:8px;&quot;&gt;abx:&amp;nbsp;&lt;/p&gt;" vertex="1">
+          <mxGeometry height="90" width="160" x="1760" y="-410" as="geometry" />
+        </mxCell>
       </root>
       </root>
     </mxGraphModel>
     </mxGraphModel>
   </diagram>
   </diagram>

+ 0 - 1
EsimLao/esim-vite/src/components/Footer.tsx

@@ -6,7 +6,6 @@ import { Area } from "../services/product/type";
 import { useNavigate } from "react-router-dom";
 import { useNavigate } from "react-router-dom";
 const Footer: React.FC = () => {
 const Footer: React.FC = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
-
   const navigate = useNavigate();
   const navigate = useNavigate();
 
 
   return (
   return (

+ 1 - 1
EsimLao/esim-vite/src/i18n/locales/en.json

@@ -192,7 +192,7 @@
   "weveSentVerificationCode": "We've sent a 6-digit verification code to",
   "weveSentVerificationCode": "We've sent a 6-digit verification code to",
   "verificationCode": "Verification Code",
   "verificationCode": "Verification Code",
   "codeExpiredPleaseRequestNewOne": "Code expired. Please request a new one.",
   "codeExpiredPleaseRequestNewOne": "Code expired. Please request a new one.",
-  "fastSimpleRed": "Fast. Simple. Red.",
+  "fastSimpleRed": "Fast. Simple.",
   "globalConnectivityForTheModernTraveler": "Global connectivity for the modern traveler.",
   "globalConnectivityForTheModernTraveler": "Global connectivity for the modern traveler.",
   "codeExpiresIn": "Code expires in",
   "codeExpiresIn": "Code expires in",
   "enterYourEmail": "Enter your email",
   "enterYourEmail": "Enter your email",

+ 1 - 1
EsimLao/esim-vite/src/i18n/locales/vi.json

@@ -192,7 +192,7 @@
   "weveSentVerificationCode": "Chúng tôi đã gửi mã xác minh gồm 6 chữ số đến",
   "weveSentVerificationCode": "Chúng tôi đã gửi mã xác minh gồm 6 chữ số đến",
   "verificationCode": "Mã xác minh",
   "verificationCode": "Mã xác minh",
   "codeExpiredPleaseRequestNewOne": "Mã đã hết hạn. Vui lòng yêu cầu mã mới.",
   "codeExpiredPleaseRequestNewOne": "Mã đã hết hạn. Vui lòng yêu cầu mã mới.",
-  "fastSimpleRed": "Nhanh. Đơn giản. Đỏ.",
+  "fastSimpleRed": "Nhanh. Đơn giản.",
   "globalConnectivityForTheModernTraveler": "Kết nối toàn cầu cho người du lịch hiện đại",
   "globalConnectivityForTheModernTraveler": "Kết nối toàn cầu cho người du lịch hiện đại",
   "codeExpiresIn": "Mã hết hạn sau",
   "codeExpiresIn": "Mã hết hạn sau",
   "enterYourEmail": "Nhập email của bạn",
   "enterYourEmail": "Nhập email của bạn",

+ 38 - 8
EsimLao/esim-vite/src/logic/loigicUtils.ts

@@ -10,7 +10,7 @@ export const formatCarriers = (text) => {
 export const setWithExpiry = <T>(
 export const setWithExpiry = <T>(
   key: string,
   key: string,
   value: T,
   value: T,
-  ttlMs?: number | null
+  ttlMs?: number | null,
 ) => {
 ) => {
   const now = Date.now();
   const now = Date.now();
 
 
@@ -54,7 +54,7 @@ type CurrencyCode =
 export const formatCurrency = (
 export const formatCurrency = (
   amount: number | string,
   amount: number | string,
   currency?: string,
   currency?: string,
-  locale?: string
+  locale?: string,
 ) => {
 ) => {
   if (amount === null || amount === undefined || amount === "") return "";
   if (amount === null || amount === undefined || amount === "") return "";
 
 
@@ -62,15 +62,45 @@ export const formatCurrency = (
 
 
   const resolvedLocale =
   const resolvedLocale =
     locale ??
     locale ??
-    (currency === "VND"
-      ? "vi-VN"
-      : currency === "USD"
-        ? "en-US"
-        : "en-GB");
+    (currency === "VND" ? "vi-VN" : currency === "USD" ? "en-US" : "en-GB");
 
 
   return new Intl.NumberFormat(resolvedLocale, {
   return new Intl.NumberFormat(resolvedLocale, {
     style: "currency",
     style: "currency",
     currency,
     currency,
     minimumFractionDigits: currency === "VND" ? 0 : 2,
     minimumFractionDigits: currency === "VND" ? 0 : 2,
   }).format(value);
   }).format(value);
-};
+};
+
+export const convertOrderStatusToText = (status: number) => {
+  //   1: chờ thanh toán
+  // 2: đã thanh toán, chờ xuất esim
+  // 3: thanh toán thất bại
+  // 4: đã trả esim
+  switch (status) {
+    case 1:
+      return "Chờ thanh toán";
+    case 2:
+      return "Đã thanh toán, chờ xuất eSIM";
+    case 3:
+      return "Thanh toán thất bại";
+    case 4:
+      return "Đã trả eSIM";
+    default:
+      return "Không xác định";
+  }
+};
+
+export const convertOrderStatusToColor = (type: number) => {
+  switch (type) {
+    case 1:
+      return "bg-orange-400 text-white";
+    case 2:
+      return "bg-[#00c087] text-white";
+    case 3:
+      return "bg-red-400 text-white";
+    case 4:
+      return "bg-blue-400 text-white";
+    default:
+      return "bg-slate-800 text-white";
+  }
+};

+ 20 - 45
EsimLao/esim-vite/src/pages/order-detail/OrderDetailView.tsx

@@ -10,7 +10,12 @@ import { useMutation } from "@tanstack/react-query";
 import React, { useState, useEffect } from "react";
 import React, { useState, useEffect } from "react";
 import { useLocation, useNavigate } from "react-router-dom";
 import { useLocation, useNavigate } from "react-router-dom";
 import { openQRModal } from "../../features/popup/popupSlice";
 import { openQRModal } from "../../features/popup/popupSlice";
-import { formatCurrency, formatNumber } from "../../logic/loigicUtils";
+import {
+  convertOrderStatusToColor,
+  convertOrderStatusToText,
+  formatCurrency,
+  formatNumber,
+} from "../../logic/loigicUtils";
 import { useTranslation } from "react-i18next";
 import { useTranslation } from "react-i18next";
 import { format } from "path";
 import { format } from "path";
 
 
@@ -72,7 +77,7 @@ const OrderDetailView = () => {
             }
             }
 
 
             return null;
             return null;
-          })
+          }),
         );
         );
 
 
         const validResults = results.filter(Boolean);
         const validResults = results.filter(Boolean);
@@ -101,7 +106,7 @@ const OrderDetailView = () => {
 
 
     const percentage = Math.min(
     const percentage = Math.min(
       Math.max(dataUsage.usageData / dataUsage.totalData, 0),
       Math.max(dataUsage.usageData / dataUsage.totalData, 0),
-      1
+      1,
     );
     );
     const strokeDashoffset = arcLength - percentage * arcLength;
     const strokeDashoffset = arcLength - percentage * arcLength;
 
 
@@ -181,12 +186,12 @@ const OrderDetailView = () => {
           {dataUsage.status === 0
           {dataUsage.status === 0
             ? t("notActive")
             ? t("notActive")
             : dataUsage.status === 1
             : dataUsage.status === 1
-            ? t("active")
-            : dataUsage.status === 2
-            ? t("finished")
-            : dataUsage.status === 3
-            ? t("expired")
-            : t("unknown")}
+              ? t("active")
+              : dataUsage.status === 2
+                ? t("finished")
+                : dataUsage.status === 3
+                  ? t("expired")
+                  : t("unknown")}
         </p>
         </p>
         {/* <p className="mt-1 text-slate-400 text-sm font-bold uppercase tracking-widest">
         {/* <p className="mt-1 text-slate-400 text-sm font-bold uppercase tracking-widest">
           {100 - Math.round((used / total) * 100)}% {t("remaining")}
           {100 - Math.round((used / total) * 100)}% {t("remaining")}
@@ -195,16 +200,6 @@ const OrderDetailView = () => {
     );
     );
   };
   };
 
 
-  const getStatusColor = (status: number) => {
-    switch (status) {
-      case 2:
-        return "bg-[#00c087] text-white";
-      case 1:
-        return "bg-orange-400 text-white";
-      default:
-        return "bg-slate-800 text-white";
-    }
-  };
   return (
   return (
     <div className="bg-[#fcfdfe] min-h-screen pb-20">
     <div className="bg-[#fcfdfe] min-h-screen pb-20">
       {/* Breadcrumb */}
       {/* Breadcrumb */}
@@ -285,31 +280,11 @@ const OrderDetailView = () => {
                   {state.orderHistory?.orderCode}
                   {state.orderHistory?.orderCode}
                 </span>
                 </span>
               </div>
               </div>
-              {state.orderHistory?.status === 2 ? (
-                <span
-                  className={`px-3 py-1 rounded-md text-sm font-bold shadow-sm ${getStatusColor(
-                    state.orderHistory?.status
-                  )}`}
-                >
-                  {t("paymentSuccessful")}
-                </span>
-              ) : state.orderHistory?.status === 1 ? (
-                <span
-                  className={`px-3 py-1 rounded-md text-sm font-bold shadow-sm ${getStatusColor(
-                    state.orderHistory?.status
-                  )}`}
-                >
-                  {t("pendingPayment")}
-                </span>
-              ) : (
-                <span
-                  className={`px-3 py-1 rounded-md text-sm font-bold shadow-sm ${getStatusColor(
-                    state.orderHistory?.status
-                  )}`}
-                >
-                  {t("failure")}
-                </span>
-              )}
+              <span
+                className={`px-3 py-1 rounded-md text-sm font-bold shadow-sm ${convertOrderStatusToColor(state.orderHistory?.status)}`}
+              >
+                {convertOrderStatusToText(state.orderHistory?.status)}
+              </span>
             </div>
             </div>
 
 
             {/* Tabs */}
             {/* Tabs */}
@@ -342,7 +317,7 @@ const OrderDetailView = () => {
                 {t("totalTotal")}:{" "}
                 {t("totalTotal")}:{" "}
                 {formatCurrency(
                 {formatCurrency(
                   state.orderHistory?.paymentMoney,
                   state.orderHistory?.paymentMoney,
-                  state.orderHistory?.curency
+                  state.orderHistory?.curency,
                 )}{" "}
                 )}{" "}
                 {/* <span className="text-slate-500 font-normal">
                 {/* <span className="text-slate-500 font-normal">
                   ({state.orderHistory?.curency})
                   ({state.orderHistory?.curency})

+ 16 - 22
EsimLao/esim-vite/src/pages/order-history/OrderHistoryView.tsx

@@ -5,7 +5,12 @@ import { useAppDispatch } from "../../hooks/useRedux";
 import { OrderHistory } from "../../services/product/type";
 import { OrderHistory } from "../../services/product/type";
 import { useMutation } from "@tanstack/react-query";
 import { useMutation } from "@tanstack/react-query";
 import React, { useState, useEffect } from "react";
 import React, { useState, useEffect } from "react";
-import { formatCurrency, formatNumber } from "../../logic/loigicUtils";
+import {
+  convertOrderStatusToColor,
+  convertOrderStatusToText,
+  formatCurrency,
+  formatNumber,
+} from "../../logic/loigicUtils";
 import { useTranslation } from "react-i18next";
 import { useTranslation } from "react-i18next";
 
 
 const OrderHistoryView = () => {
 const OrderHistoryView = () => {
@@ -56,17 +61,6 @@ const OrderHistoryView = () => {
   const inputClass =
   const inputClass =
     "w-full bg-slate-50 border-2 border-transparent focus:border-[#EE0434]/20 rounded-2xl py-3 px-5 focus:outline-none focus:bg-white transition-all text-slate-700 font-bold placeholder:text-slate-300 text-sm md:text-base h-[50px]";
     "w-full bg-slate-50 border-2 border-transparent focus:border-[#EE0434]/20 rounded-2xl py-3 px-5 focus:outline-none focus:bg-white transition-all text-slate-700 font-bold placeholder:text-slate-300 text-sm md:text-base h-[50px]";
 
 
-  const getStatusColor = (status: number) => {
-    switch (status) {
-      case 2:
-        return "bg-[#00c087] text-white";
-      case 1:
-        return "bg-orange-400 text-white";
-      default:
-        return "bg-slate-800 text-white";
-    }
-  };
-
   // const filteredOrders = orders.filter((order) => {
   // const filteredOrders = orders.filter((order) => {
   //   const matchesSearch = order.id.includes(searchOrder);
   //   const matchesSearch = order.id.includes(searchOrder);
   //   const matchesStatus = status === "-1" || order.status === status;
   //   const matchesStatus = status === "-1" || order.status === status;
@@ -173,9 +167,13 @@ const OrderHistoryView = () => {
                 getOrderMutation.mutate();
                 getOrderMutation.mutate();
               }}
               }}
             >
             >
-              <option value="-1">Status</option>
-              <option value="2">Success</option>
-              <option value="1">Pending payment</option>
+              {/* 1: chờ thanh toán 2: đã thanh toán, chờ xuất esim 3: thanh toán
+              thất bại 4: đã trả esim */}
+              <option value="-1">Trạng thái</option>
+              <option value="1">Chờ thanh toán</option>
+              <option value="2">Đã thanh toán, chờ xuất eSIM</option>
+              <option value="3">Thanh toán thất bại</option>
+              <option value="4">Đã trả eSIM</option>
             </select>
             </select>
             <svg
             <svg
               className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400 pointer-events-none"
               className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400 pointer-events-none"
@@ -214,15 +212,11 @@ const OrderHistoryView = () => {
               >
               >
                 <div className="space-y-3">
                 <div className="space-y-3">
                   <span
                   <span
-                    className={`inline-block px-3 py-1 rounded-lg text-xs font-black uppercase tracking-wider ${getStatusColor(
-                      order.status
+                    className={`inline-block px-3 py-1 rounded-lg text-xs font-black uppercase tracking-wider ${convertOrderStatusToColor(
+                      order.status,
                     )}`}
                     )}`}
                   >
                   >
-                    {order.status === 2
-                      ? "Success"
-                      : order.status === 1
-                      ? "Pending payment"
-                      : "Failed"}
+                    {convertOrderStatusToText(order.status)}
                   </span>
                   </span>
                   <div>
                   <div>
                     <p className="text-xl font-black text-slate-900 tracking-tight">
                     <p className="text-xl font-black text-slate-900 tracking-tight">

+ 29 - 25
EsimLao/esim-vite/src/pages/product-detail/ProductDetailView.tsx

@@ -25,7 +25,7 @@ const ProductDetailView: React.FC = () => {
   const dispatch = useAppDispatch();
   const dispatch = useAppDispatch();
   const { t } = useTranslation();
   const { t } = useTranslation();
   // let area = location.state as Area;
   // let area = location.state as Area;
-  const areas = getWithExpiry<Area[] | []>("areas");
+  const areas = getWithExpiry<Area[]>("areas");
   const { id } = useParams<{ id: string }>();
   const { id } = useParams<{ id: string }>();
   const loading = useAppSelector((state) => state.loading);
   const loading = useAppSelector((state) => state.loading);
   const [selectedDays, setSelectedDays] = useState<number>(null);
   const [selectedDays, setSelectedDays] = useState<number>(null);
@@ -111,6 +111,10 @@ const ProductDetailView: React.FC = () => {
     },
     },
   });
   });
 
 
+  const convertPackageToSelectedProduct = (packg: Package) => {
+    return packg.title;
+  };
+
   const options = useMemo(() => {
   const options = useMemo(() => {
     console.log("Calculating options from loadPackage");
     console.log("Calculating options from loadPackage");
 
 
@@ -119,20 +123,20 @@ const ProductDetailView: React.FC = () => {
 
 
     packages.forEach((p) => {
     packages.forEach((p) => {
       daysSet.add(p.dayDuration);
       daysSet.add(p.dayDuration);
-      dataSet.add(p.amountData.toString());
+      dataSet.add(convertPackageToSelectedProduct(p));
     });
     });
 
 
     const daysArray = Array.from(daysSet).sort((a, b) => a - b);
     const daysArray = Array.from(daysSet).sort((a, b) => a - b);
 
 
-    const dataArray = Array.from(dataSet).sort((a, b) => {
-      if (a === "Unlimited") return 1;
-      if (b === "Unlimited") return -1;
-      return parseInt(a) - parseInt(b);
-    });
+    // const dataArray = Array.from(dataSet).sort((a, b) => {
+    //   if (a === "Unlimited") return 1;
+    //   if (b === "Unlimited") return -1;
+    //   return parseInt(a) - parseInt(b);
+    // });
 
 
     return {
     return {
       daysArray,
       daysArray,
-      dataArray,
+      dataArray: Array.from(dataSet),
     };
     };
   }, [packages]);
   }, [packages]);
 
 
@@ -154,20 +158,20 @@ const ProductDetailView: React.FC = () => {
     const dataSet = new Set<string>();
     const dataSet = new Set<string>();
     packages.forEach((p) => {
     packages.forEach((p) => {
       if (p.dayDuration === day) {
       if (p.dayDuration === day) {
-        dataSet.add(p.amountData.toString());
+        dataSet.add(convertPackageToSelectedProduct(p));
       }
       }
     });
     });
     setSelectedDays(day);
     setSelectedDays(day);
     setSelectedData(
     setSelectedData(
-      dataSet.has(selectedData) ? selectedData : Array.from(dataSet)[0]
+      dataSet.has(selectedData) ? selectedData : Array.from(dataSet)[0],
     );
     );
     setDataActiveOptions(Array.from(dataSet));
     setDataActiveOptions(Array.from(dataSet));
     setSelectedPackage(
     setSelectedPackage(
       packages.find(
       packages.find(
         (p) =>
         (p) =>
           p.dayDuration === selectedDays &&
           p.dayDuration === selectedDays &&
-          p.amountData.toString() === selectedData
-      )
+          convertPackageToSelectedProduct(p) === selectedData,
+      ),
     );
     );
   };
   };
 
 
@@ -175,21 +179,21 @@ const ProductDetailView: React.FC = () => {
     // filter day options based on selected data if needed
     // filter day options based on selected data if needed
     const daysSet = new Set<number>();
     const daysSet = new Set<number>();
     packages.forEach((p) => {
     packages.forEach((p) => {
-      if (p.amountData.toString() === data) {
+      if (convertPackageToSelectedProduct(p) === data) {
         daysSet.add(p.dayDuration);
         daysSet.add(p.dayDuration);
       }
       }
     });
     });
     setSelectedData(data);
     setSelectedData(data);
     setSelectedDays(
     setSelectedDays(
-      daysSet.has(selectedDays) ? selectedDays : Array.from(daysSet)[0]
+      daysSet.has(selectedDays) ? selectedDays : Array.from(daysSet)[0],
     );
     );
     setDaysActiveOptions(Array.from(daysSet));
     setDaysActiveOptions(Array.from(daysSet));
     setSelectedPackage(
     setSelectedPackage(
       packages.find(
       packages.find(
         (p) =>
         (p) =>
           p.dayDuration === selectedDays &&
           p.dayDuration === selectedDays &&
-          p.amountData.toString() === selectedData
-      )
+          convertPackageToSelectedProduct(p) === selectedData,
+      ),
     );
     );
   };
   };
 
 
@@ -200,7 +204,7 @@ const ProductDetailView: React.FC = () => {
     let selectedPackageTmp = packages.find(
     let selectedPackageTmp = packages.find(
       (p) =>
       (p) =>
         p.dayDuration === selectedDays &&
         p.dayDuration === selectedDays &&
-        p.amountData.toString() === selectedData
+        convertPackageToSelectedProduct(p) === selectedData,
     );
     );
     if (!selectedPackageTmp) {
     if (!selectedPackageTmp) {
       // console.log(
       // console.log(
@@ -218,7 +222,7 @@ const ProductDetailView: React.FC = () => {
     }
     }
     console.log(
     console.log(
       "Selected package: ",
       "Selected package: ",
-      selectedPackageTmp + " quantity " + quantityToUse
+      selectedPackageTmp + " quantity " + quantityToUse,
     );
     );
     setPrices({
     setPrices({
       original: quantityToUse * selectedPackageTmp.displayPrice,
       original: quantityToUse * selectedPackageTmp.displayPrice,
@@ -241,7 +245,7 @@ const ProductDetailView: React.FC = () => {
     const selectedPackage = packages.find(
     const selectedPackage = packages.find(
       (p) =>
       (p) =>
         p.dayDuration === selectedDays &&
         p.dayDuration === selectedDays &&
-        p.amountData.toString() === selectedData
+        convertPackageToSelectedProduct(p) === selectedData,
     );
     );
     if (!selectedPackage) {
     if (!selectedPackage) {
       alert("Please select a valid package");
       alert("Please select a valid package");
@@ -272,7 +276,7 @@ const ProductDetailView: React.FC = () => {
           title: "Checkout Error",
           title: "Checkout Error",
           message: res.message || "Failed to proceed to checkout.",
           message: res.message || "Failed to proceed to checkout.",
           buttonText: "Close",
           buttonText: "Close",
-        })
+        }),
       );
       );
     }
     }
   };
   };
@@ -368,8 +372,8 @@ const ProductDetailView: React.FC = () => {
                     selectedDays === day
                     selectedDays === day
                       ? "border-[#EE0434] text-white bg-[#EE0434] shadow-md"
                       ? "border-[#EE0434] text-white bg-[#EE0434] shadow-md"
                       : daysActiveOptions.includes(day)
                       : daysActiveOptions.includes(day)
-                      ? "border-[#ffffff] text-black bg-[#ffffff] shadow-md"
-                      : "border-slate-100 text-slate-300"
+                        ? "border-[#ffffff] text-black bg-[#ffffff] shadow-md"
+                        : "border-slate-100 text-slate-300"
                   }`}
                   }`}
                 >
                 >
                   {day}
                   {day}
@@ -394,11 +398,11 @@ const ProductDetailView: React.FC = () => {
                     selectedData === data
                     selectedData === data
                       ? "border-[#EE0434] text-white bg-[#EE0434] shadow-md"
                       ? "border-[#EE0434] text-white bg-[#EE0434] shadow-md"
                       : dataActiveOptions.includes(data)
                       : dataActiveOptions.includes(data)
-                      ? "border-[#ffffff] text-black bg-[#ffffff] shadow-md"
-                      : "border-slate-100 text-slate-300"
+                        ? "border-[#ffffff] text-black bg-[#ffffff] shadow-md"
+                        : "border-slate-100 text-slate-300"
                   }`}
                   }`}
                 >
                 >
-                  {data === "0" ? "Unlimited" : data + " GB"}
+                  {data === "0" ? "Unlimited" : data}
                 </button>
                 </button>
               ))}
               ))}
             </div>
             </div>

+ 5 - 7
EsimLao/esim-vite/src/pages/terms/TermsView.tsx

@@ -365,17 +365,15 @@ const TermsView = () => {
                 </h3>
                 </h3>
                 <ul className="list-disc pl-5 mt-2 space-y-1">
                 <ul className="list-disc pl-5 mt-2 space-y-1">
                   <li>
                   <li>
-                    <strong>Tên doanh nghiệp:</strong> CÔNG TY CỔ PHẦN GIẢI PHÁP
-                    CÔNG NGHỆ WELLZONE
+                    <strong>Tên doanh nghiệp:</strong> CÔNG TY TNHH Phát triển
+                    toàn cầu VIETTECH
                   </li>
                   </li>
                   <li>
                   <li>
-                    <strong>Giấy chứng nhận ĐKKD:</strong> 0109310641 do Phòng
-                    Đăng ký kinh doanh – Sở Kế hoạch và Đầu tư Hà Nội cấp lần
-                    đầu ngày 17/08/2020
+                    <strong>Giấy chứng nhận ĐKKD:</strong> 0901210362
                   </li>
                   </li>
                   <li>
                   <li>
-                    <strong>Trụ sở chính:</strong> Tầng 10, 83B Lý Thường Kiệt,
-                    Phường Cửa Nam, Thành phố Hà Nội
+                    <strong>Trụ sở chính:</strong> Số 218, Đảo Dừa 1, Khu đô thị
+                    Vinhomes Ocean Park 2, Xã Nghĩa Trụ, Tỉnh Hưng Yên, Việt Nam
                   </li>
                   </li>
                 </ul>
                 </ul>