انتقل إلى المحتوى الرئيسي

صفحة المراقبة

صورة صفحة المراقبة

فايلات الفولدر

api.ts;
MonitorDeliveryTables.tsx;
MonitorTable.tsx;
useMonitorStore.ts;
useMonitor.ts;
MonitorView.tsx;

api.ts

export const getAllTables = async (filter: string): Promise<MonitorTable[]> => {
const params = new URLSearchParams({});
params.set("status", filter);
const response = await axiosInstance.get(
`/checkout/halls/tables?${params.toString()}`
);
return response.data;
};
  • هذا راح يرجع الطاولات حسب الفلتر
    • status = All : هاي راح ترجع كل الطاولات سواء متاحة او مشغولة
    • status = Free ترجع الطاولات المتاحة وبس
    • status = Busy ترجع الطاولات المشغولة
export const getCheckoutHalls = async (): Promise<MonitorHall[]> => {
const response = await axiosInstance.get("/checkout/halls");
return response.data;
};
  • هذا راح يرجع القاعات ويا عدد الطاولات مالتها
export const getHallTables = async (
hallId: number,
filter: string
): Promise<MonitorTable[]> => {
const params = new URLSearchParams({});
params.set("status", filter);
params.set("hallId", hallId.toString());
const response = await axiosInstance.get(
`/checkout/halls/tables?${params.toString()}`
);
return response.data;
};
  • وفي حال اكو hallId هنا راح ياخذ المعرف وراح يسويلي فلتر على القاعات والطاولات

MonitorDeliveryTables.tsx

بهاي الصفحة من راح نضغط على زر السفري الموجود بالمراقبة راح يعرض الطاولات الي عندي الخاصة بالدلفري وهنا راح يستخدم هذا ال Component علمود يعرضها

<>
<div className="flex items-center justify-between">
<div className="text-xl font-bold">
{t("pages.monitor.deliveryOrdersSection")}
</div>
<div>
<Button
className="py-8 px-6"
onClick={() => {
createNewSafariBillMutation.mutate();
}}
>
{t("pages.monitor.createDeliveryOrder")}
</Button>
</div>
</div>
<div className="mt-4 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 :grid-cols-5 gap-4">
{isSuccess &&
deliveryTables.map((bill) => <DeliveryTable billData={bill} />)}
</div>
</>
  • هذي الواجهة الي راح ترجع النة , بس اهم شي بهذا ال Component هو الي راح يفر عليه والي هو

    • DeliveryTable :
<button
key={String(bill.id)}
className={`relative rounded-2xl px-2 py-3 ${getDeliveryTableColor(
bill.orderStatus!,
!!bill.deliveryDriverId
)} dark:bg-[#27252C] hover:bg-gray-500/10 dark:hover:bg-white/15 flex flex-col flex-wrap items-start gap-3`}
onClick={() => {
navigate(`/safari/${bill.id}`);
}}
>
<div className="flex flex-col items-start gap-1 flex-1">
<div className="flex flex-col items-start gap-2">
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
<div className="justify-self-end">رقم الطلب:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.id}
</div>
{/* <div className="justify-self-end">الحالة:</div>
<div className="justify-self-start font-bold col-span-1"> {bill.orderStatus}</div> */}
<div className="justify-self-end">اسم الزبون:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.customerName || "زبون نقدي"}
</div>
<div className="justify-self-end">رقم الزبون:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.customerPhoneNumber}
</div>
<div className="justify-self-end">الكاشير:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.cashierName}
</div>
<div className="justify-self-end">اسم السائق:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.deliveryDriverName}
</div>
<div className="justify-self-end">يجهز بعد:</div>
<div className="justify-self-start font-bold col-span-1">
<Timer
type={TimerType.CountDown}
launchDate={addMinutesToDate(
bill.prepTime!,
new Date(bill.orderDate!)
).toISOString()}
/>
</div>
<div className="justify-self-end">الوقت:</div>
<div className="justify-self-start font-bold col-span-1">
<Timer type={TimerType.CountUp} launchDate={bill.orderDate!} />
</div>
</div>
</div>
</div>
{bill.deliveryDriverId && (
<>
<div className="absolute top-1 end-2 text-[50px] text-black/50">
<MdDeliveryDining />
</div>
</>
)}
</button>
  • هنا هذا Component الي راح يكعد يعرض طاولة وحدة وراح يستقبل بيانات الفاتورة وراح يستخدم getDeliveryTableColor علمود يرجع ستايل بناء على حالة الاوردر
  • باقي التفاصيل بال Component هي مجرد عرض للبيانات مال الاوبجكت
export function getDeliveryTableColor(
orderStatus: string,
isDelivery: boolean
) {
let color = "bg-input";

switch (orderStatus) {
case "NeedsPrintingToKitchen":
color = "bg-yellow-100 hover:bg-yellow-200";
break;
case "NeedsPrintingToCustomer":
color = "bg-purple-100 hover:bg-purple-200";
break;
case "PrintedToCustomer":
color = "bg-sky-100 hover:bg-sky-200";
break;
case "Open":
color = "bg-[#F6F6F9]";
break;
case "Closed":
color = "bg-red-100 hover:bg-red-200";
break;
default:
break;
}

if (isDelivery) {
switch (orderStatus) {
case "NeedsPrintingToKitchen":
color = "bg-yellow-100 hover:bg-yellow-200";
break;
case "NeedsPrintingToCustomer":
color = "bg-purple-100 hover:bg-purple-200";
break;
case "PrintedToCustomer":
color = "bg-orange-100 hover:bg-orange-200";
break;
case "Open":
color = "bg-[#F6F6F9]";
break;
case "Closed":
color = "bg-red-100 hover:bg-red-200";
break;
default:
break;
}
}

return cn(color);
}
  • هاي مجموعة الحالات والشروط مالتها والستايل مال كل وحدة منهن

useCheckoutStore.ts ( فقط جزئية Monitor Types )

export type MonitorHall = {
id: number;
hallName: string;
tables: number;
};

export type MonitorTable = {
id: number;
tableNumber: number;
orderTime: string;
status: string;
prepTime: number;
capacity: number;
numberOfItemsOnTheTable: number;
hallId: number;
hallName: string;
};
  • هذني الانواع الي راح يتم استخدامهن باللوجك مال المراقبة مالتك بدال ما كلسع تكتب الانواع وتسوي set للبيانات مالتك

MonitorTable.tsx

type TableViewProps = {
table: MonitorTableType;
customClickFunction?: () => void;
createLabel?: string;
};
  • هنا حيكون التايب مال ال View الي همينة راح يستخدم MonitorTableType
function getTableColor(orderStatus: string) {
let color = "text-[#55C023]";
switch (orderStatus) {
case "NeedsPrintingToKitchen":
color = "text-yellow-500";
break;
case "NeedsPrintingToCustomer":
color = "text-purple-500";
break;
case "PrintedToCustomer":
color = "text-sky-500";
break;
case "Busy":
color = "text-red-500";
break;
case "Free":
color = "text-[#55C023]";
break;
default:
break;
}

return cn(color);
}
  • هنانة راح يسوي switch للون حسب الحالة مال الطلب
useEffect(() => {
const handleOrderUpdate = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: bill.prepTime || 0 });
}
};

const handleOrderCreated = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: bill.prepTime || 0 });
}
};

const handleOrderDeleted = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: 0 });
}
};

const handleOrderFinished = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: 0 });
}
};

subscribe("OrderUpdate", handleOrderUpdate);
subscribe("OrderCreated", handleOrderCreated);
subscribe("OrderDelete", handleOrderDeleted);
subscribe("OrderFinished", handleOrderFinished);

return () => {
unsubscribe("OrderUpdate", handleOrderUpdate);
unsubscribe("OrderCreated", handleOrderCreated);
unsubscribe("OrderDelete", handleOrderDeleted);
unsubscribe("OrderFinished", handleOrderFinished);
};
}, [subscribe, unsubscribe, table]);
  • هنا يخص عمليات خاصة بالمراقبة مثل تحديث والحذف وغيرها وراح يخزن القيم global عن طريق ال subscribe method

  • الباقي حيكون عرض لل UI مالتك بالصفحة وياه بعض اللوجك البسيط الي يخص العرض والستايل


useMonitorStore.tsx

export type MonitorHall = {
id: number;
hallName: string;
tables: number;
};

type MonitorStore = {
selectedHall?: MonitorHall;
selectedTable?: MonitorTable;

setSelectedHall: (hall?: MonitorHall) => void;
setSelectedTable: (table?: MonitorTable) => void;
};
  • هاي عبارة عن Types راح يتم استخدامها بال CustomHook الاساسي الي راح نشوفة بعد شوية وبيها قيم خاصة بالقاعة والطاولات
const useMonitorStore = create<MonitorStore>((set) => ({
selectedHall: undefined,
selectedTable: undefined,

setSelectedHall: (hall?: MonitorHall) => {
set((state) => ({
selectedHall: hall,
}));
},

setSelectedTable: (table?: MonitorTable) => {
set((state) => ({
selectedTable: table,
}));
},
}));
  • هاي راح تسوي Setting للقاعة والطاولة وراح تستقبل الانواع الفوك اضافة للtype الي شفناه من صفحة ال useCheckoutStore

useMonitor

export enum MonitorGroup {
AllTables = 0,
SelectedHall = 1,
Safari = 2,
}

export default function useMonitor() {
const [searchParams] = useSearchParams();
const [group, setGroup] = useState<MonitorGroup>(MonitorGroup.AllTables)
const [hallFilter, setHallFilter] = useState("All")
const [allTablesCount, setAllTablesCount] = useState<number>(0);
const [allTablesFilter, setAllTablesFilter] = useState("All")
const { selectedHall, setSelectedHall, selectedTable, setSelectedTable } = useMonitorStore();

const { data: halls, isLoading: isHallsLoading, isError: isHallsError } = useQuery<MonitorHall[]>({
queryKey: ["checkout-halls"],
queryFn: () => getCheckoutHalls(),
});
  • اول شي عدنة ال Enum الخاص بتحديد هل المجموعة الحالية هي الطاولات كلها ام مختار قاعة او رايح على السفري
  • ثاني شي عدنة مجموعة من ال States ومن ضمنها الخاصة باستخدام ال MonitorGroup وايضا عدنة هنا Get Request الي راح يجيب القاعات كلها
const {
data: tables,
isLoading: isTablesLoading,
isError: isTablesError,
} = useQuery<MonitorTable[]>({
queryKey: ["monitor-hall-tables", selectedHall?.id, hallFilter],
queryFn: () => {
return getHallTables(selectedHall?.id!, hallFilter);
},
enabled: !!selectedHall?.id && !!hallFilter,
});

const {
data: allTables,
isLoading: isAllTablesLoading,
isError: isAllTablesError,
} = useQuery<MonitorTable[]>({
queryKey: ["monitor-all-tables", allTablesFilter],
queryFn: () => {
return getAllTables(allTablesFilter);
},
enabled: !!allTablesFilter,
});
  • دالتين
    • getHallTables : راح ترجع الطاولات حسب القاعة المختارة مالتك وحسب الفلتر الداخل بيها
    • getAllTables : راح ترجع كل الطاولات مالتي وياها الفلتر الداخل عليها
useEffect(() => {
const groupParam = Number.parseInt(searchParams.get("group") || "0");
const hallParam = Number.parseInt(searchParams.get("hall") || "-1");
switch (groupParam) {
case 0:
setGroup(MonitorGroup.AllTables);
break;
case 1:
setGroup(MonitorGroup.SelectedHall);
if (hallParam != -1) {
for (const hall of halls ?? []) {
if (hall.id == hallParam) {
setSelectedHall(hall);
}
}
}
break;
case 2:
setGroup(MonitorGroup.Safari);
break;
default:
break;
}
}, [searchParams, halls]);
  • هاي راح تسوي Set للقيمة مال المجموعة الحالية بناء على المعطيات والي هي اما كل الطاولات = 0 او القاعة المختارة = 1او سفري = 2

والي كل وحدة راح يكون الها مرادف بال Enum الي شفناه فوك قبل شوية


monitorView.tsx

const { $can } = useUserPermissionsStore();
const canHandleDeliveryOrders = $can(AllPermissions.HandleDeliveryOrders);
  • هذا عبارة عن Permission راح نشرحة بعدين بالملفات المشتركة , بس بشكل عام هذا راح يخليني اروح لقائمة السفري والتعاملات مالتها لو لا والي راح يتم اضافة هاي ال Permission من فولدر الادارة من يم الادوار
function getFilterValue() {
if (group == MonitorGroup.AllTables) {
return allTablesFilter;
} else if (group == MonitorGroup.SelectedHall) {
return hallFilter;
}
}

function setFilterValue(e: any) {
if (group == MonitorGroup.AllTables) {
setAllTablesFilter(e);
return;
} else if (group == MonitorGroup.SelectedHall) {
setHallFilter(e);
return;
}
}
  • هذني الدالتين getFilterValue و setFilterValue وظيفتهن يشتغلن حسب قيمة المتغير group، واللي يحدد نوع الفلترة اللي تريد تشتغل عليها (يا جدول تريد تصفي).

    getHallFilter

  • هاي ترجع قيمة الفلتر الحالي حسب نوع group:

إذا group هو AllTables، ترجع allTablesFilter.

إذا group هو SelectedHall، ترجع hallFilter

setHallFilter هاي تستقبل قيمة جديدة e، وتحدث بيها الفلتر الصحيح حسب group:

إذا group هو AllTables، تنفذ setAllTablesFilter(e).

إذا group هو SelectedHall، تنفذ setHallFilter(e). الباقي هو ال UI الي راح ينعرض بالصفحة ويا لوجك خاص بالعرض