From 2bbfe86cb139ddd360f3d35fddea5f2d5d9dadc1 Mon Sep 17 00:00:00 2001 From: Reza Taghizadeh <95388378+srt207-reza@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:03:59 +0330 Subject: [PATCH] fix: reslove some bugs (v3.122.490) --- android.keystore | Bin 2682 -> 0 bytes package.json | 2 +- public/.well-known/assetlinks.json | 11 +- signing.keystore | Bin 0 -> 2696 bytes src/apps/new-ui/Utils/removeLocalStorage.ts | 56 +++++++ src/apps/new-ui/Utils/selectedServiceStore.ts | 60 +++++++ .../AppointmentComponents/Services.tsx | 158 +++++++++--------- .../pages/CheckTimeSlotCustomer/index.tsx | 7 +- .../pages/CheckTimeSlotGeneral/index.tsx | 7 +- .../+components/HolidayManagement.tsx | 5 +- .../PersonnelCheckTimeSlotCustomer/index.tsx | 7 +- .../PersonnelCheckTimeSlotGeneral/index.tsx | 7 +- .../+components/AddService.tsx | 2 +- 13 files changed, 224 insertions(+), 98 deletions(-) delete mode 100644 android.keystore create mode 100644 signing.keystore create mode 100644 src/apps/new-ui/Utils/removeLocalStorage.ts create mode 100644 src/apps/new-ui/Utils/selectedServiceStore.ts diff --git a/android.keystore b/android.keystore deleted file mode 100644 index 76491275dcec40a4db4fc23f03f7caa0047fcb01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2682 zcma);X*d*&7RP7C3`|9}4H*18WDzV+`ksy#bI|ztEvoSLN=OPFS0iXpLq4x2*KoOB*g=(9J2O2WY{Rz_p$H4CtE!C?aXCzfa#CNN_9O4nji8zig+;Td zWVxhVF(I0=tKDMzc`RZTv9%r>VYOa(*1D3b>A@R<72n73%xj-{IFL1~JnJ5{-mw0i_?4z$E2O#dsVN=Y+`(tfoUfj_aK{mOL`s)` zZlz#3Ik^dqKUFZwt+qI~r2-OSkagPpYEc+<8x(A)?!0?xX9A_n9&zBGTT@r9qI|Jh z&zHo%qPmsZpYtu|!Z3?jz*yXf7icQwhpJzA=GCss=$_jzYN=nzjb>`g+c~jhZPEu9 zQ>C@&fC#o$2h)+HZPz;$Kt61K8F)~m9vKZJ=)2>@kGY{PFa~7hZOnzy=pRzszlodkA5Qfj_`?;Nx^1D5U9Zn$%JC)SG> zA@;*BB`-IVn+j0>pabBH@#5GJ15m1VN zzgq6Iw`TA16BN5 z4FcYOrk?23I3{jbEhm*D%Sv)OA+Kl9S5$_CGdSCxb$n_K>k+v4N%1r=VK$vHUdqP? zf@|(>n+edBeCn1K$fWKc5dmFl*j5OCdgxhoXdaMVd|*3_s!JTJ`_>>Dr0`0)?_OgL zU3U^NNALa#w8dMO&)Wr1aK#$CTVM1oC3QpM1t75^-ZzOi> zo4v`*jy0+hJEh(-h&1`dra_<>Q`t|XlS7uZxTHNhC>oA+y*=V$z^<|kXb{O&B z^3#)cN*iNo5LjjI?`jT_Of|gXeee{zcI9o!Iq$QZjvIO2Jsf8tjr3i()zFt&b1OkM3%#)r;LfDu1Pp`yd~LY-IDE%{)J&=xUUSY z2ZR3;dVfI`iomc7!2u2cAAmC;0N@Mo063$C|FO9-2r%b$4{sL~Mo9^yh(n_la99Op zGy!b#_YxB$i2%m`mefH&!0)E?j|2Q)pzd5Lsgs!tQZfKr{|oML8>egUg8Y9#J<2i@ zby;(qXXG44Xr@>O_ZA!B^iA3L^JYI5A|}MPipf7b{RnR zmTcPpmfF>RAQbvKG@)G65N6CMaG;6R%4rEhKQj-HqDkF->C~WA{@AaVb0KzhJ!YV=VV{~ODtDS=Ks|YD`$+3Y(qkdN1wF+-(xm%t z(yDIg9}h|BF=jRcFLB@Z=8?+wQJX z=U8?f2{cErBx{|VkRPg-oMR&h7tJa`2wN~&-@hFEgvwRdW^-~i;OLdtWSf#1D?HG; z_-@mj5Y)iia(TLo>Z{c(+Z*p=9Pn^RNK9fm9=`Q%JTS~wbvvO%HL3JVCBJ@cpQI+? zN=#C))VLJSMGtkp#xK-&uwUiA=+kP&``JB7k78o<4Qyl?$Os*$pVl2M2nq9q8H1C9 z>_w6-giHyWSVtPJwRng)gt&=uQv8r_`dI^Ig>}MGsTYzFrS7^6FF9TL9IWs7&D{%C zk3#Q2vu9^f2lAR5+(ufG#+Sx7)@H7an;*r=Ly|WK7o(?NG+8W_7)|;nrQOSKUve0_ zvuF37i|=Z25I?V$B4aK2ctRSLA>NN5)!Ghq(?GWffU~n|!sA zsNJP`R{!0buC)BpNp-~t@mZvNorT7rwOF3L5b8sgjwP| z07g-*xYzuPw#cb1`)hhDCY`TXYfDHwnsnbCg(=^HM_FJ5QU%D`gdTl9H!y*he;sYy LvArbvCqn)Ws?EO{ diff --git a/package.json b/package.json index dbf76e3c..4ae0f397 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "app.salona", "private": true, - "version": "3.122.486", + "version": "3.122.490", "type": "module", "scripts": { "dev": "vite --host", diff --git a/public/.well-known/assetlinks.json b/public/.well-known/assetlinks.json index cedf1f13..e7884e71 100644 --- a/public/.well-known/assetlinks.json +++ b/public/.well-known/assetlinks.json @@ -3,17 +3,10 @@ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", - "package_name": "ir.mysalona.app.twa", + "package_name": "ir.mysalona.testapp.twa", "sha256_cert_fingerprints": [ - "2B:15:95:EC:CD:A0:FB:4F:E6:8B:4A:C1:98:7A:54:14:D8:BD:A9:3E:2D:F0:5A:E6:F7:31:CD:EE:EF:6E:16:6E" + "7B:32:AD:94:28:6B:BA:72:B6:56:34:13:19:B4:B0:8A:72:3A:EC:7E:31:89:9B:D4:16:64:74:7D:93:3A:F9:16" ] } - }, - { - "relation": ["check_validation"], - "target": { - "namespace": "cafebazaar_twa", - "package_name": "ir.mysalona.app.twa" - } } ] diff --git a/signing.keystore b/signing.keystore new file mode 100644 index 0000000000000000000000000000000000000000..026eef3418f240abf53a919e10ab7ff14d8b0e0f GIT binary patch literal 2696 zcma);X*d*)7RG1B7)+M2jx3?EM24|1*~S_fV;D8rin1hGvy{OYJ7eEvt;p6)BC?I5 z5Xn;9LXr{jM@Awd*M07N`ak#6y&ukVp7XxvJs*G1L6M@Q z0V~K*2{0KddL+Y9WLD~bS*+z?GV7fqx!|aBAjkfb;)DW06=YVUBT*0K`6t23g}R8+ z{(Iy^odydqQ%rr(eIplGr7i~*UJ5T;jtp%9f#hHypd^YD!v61zAP!alN*uy*IpHkO zg9Qv!0K;ZjFiOU~G^IowvX9z@^ahi`qruuiYv23K8X@$?sukPA7vV456P(Ve!K{v- zX<`fM>X2mHF6Y?fc;S~qFee#A=-0tJO(sjWoe^nN*i+E0V?{020`F%jH zL3~M}ee*jS&nFi{5rm;-)Q8C{{;Mn&ogUR1RuK{}#OQUFeW+7-`cnhfSZ8*iP#1DZ zJ*(+gJZ-SZl;UUjHA{cW@a%xUO?(kslq4iS{bflaHGAwzLbe~t^0y|rJ>Q-Q_w}Dj zBcl)}VXD^`t`*sBWj%9a$#J+Uq@l_Q!PeTUHrPc^jxEnP*gMZ`*^lhJg*QL*|m^{D9uU<)Ir9rRP&2%3{i9 z8xJBzvgEzAK1rA@?S1GJ#hZE(2#~pTD3R?}Cg&2)I+u%>z5Q^|xnEks#Bp{rJSZs> zrxom&J;@(&3G?e|sps!Xv}W7{M}s+C(+(7j*@_=_KfQI}-zZifkFM=%5OrA~ea%^G zDZ!Ffm*2&iv(DH%nH2Sxd(hsx z8z2dv`=gq&X%ngG?l%ZBG+{usZETvyHV>P^YITrWl=&YYLA#6^_MgF|-Wx8*au>s- z-}J;iGzY!c5m(|f7D?hUB(Bm{NBNpHa}{^AO(GqVUVlR_)nM)IT<*v?&%sU$oq=3w z+4tU_;8tB%Ux*l*-ba9RY2_u1kHhjSb~Eg4a;xjtI;B=pd#|!pb=V0?K+1BH_i}Dh z=?=&<-)?i^cAl3GJ%XBA}SiilBHkLo6mW4 z!giLY6k;oVg~*)*E}o9E-AIOT zFD>&LCC{O+vcmE~|{(G-gCP;c5iTNT&M@c@|84*_?v*f<~s1)5C4mtJ&T>49nH6j#HzDr82V7 zkvQbleXJFm4yr=8qJlZ~d95|c)Hpgl9dBUb5<@rWxf8KlA;#48xB2jTCR(Rm)xZ z?xw%D{Yg&`;fm@u%JHqIR;Gjr-9uNtiq?|Z@1hk^YO^}q>Zz}C0@c6(vAQZKyw&;X zsn|C7OhMp@U>(8YVito6>G-UsUGH?|=YhEE-?ZmLXp*`wMm2H={4ah~elcu%dsH^T zvwZIm&(v=D5f`G%9|ACzKx-6tn9N9jlvQ=gMPAZW4fD0+-z7}H;|?|H*Jqv-DRk8i zKe$Y)#SqD|eDhMyT?^Ax{Ac+gv7SDTB87$6^`3=WQ zJ%U^5b>IH5`CVCej^G#?8N)sI`ubY~@#9k9UymP_X^lngHeriXrmKr?CB>l($&}Me zx=L{!6Gbx4+NXIHJ*Lu<>PC~}H%|e$wzCC*d0V6BiE2-MR!YkL!M$9pyBN?53~w0c zl(5}+P561^6TK#bZ{bo_uy9ta;qs2}IaLAp;Xvyv+_+F;n4+ARh~txW&{`$T57D4u zuH*GJ>7AU6?c&dU$m=+*^_8!8tLsuqFOSt`S?O)zl(B}{8?1y_-4o^ff)8zHdH<5_ zy>o41SaSyp%=rU#ssO2CHAd>f1y%aK8e>RW=tN3uZh}hs85ji!ljUx>i__?0fL5 z{Or&t>#uCB-Ut_CIgPSdL!zYB%suI0;F4;kO=iL7q6kf6@r=k)2cuFsr}qQ`Wq85kxFg gw5=B`@Hsj4xHwmLMv{@gr4~tTzixyV{x78b69BNz-~a#s literal 0 HcmV?d00001 diff --git a/src/apps/new-ui/Utils/removeLocalStorage.ts b/src/apps/new-ui/Utils/removeLocalStorage.ts new file mode 100644 index 00000000..aa6a76b1 --- /dev/null +++ b/src/apps/new-ui/Utils/removeLocalStorage.ts @@ -0,0 +1,56 @@ +export function clearExceptPredicate(predicate: any) { + for (let i = localStorage.length - 1; i >= 0; i--) { + const key: any = localStorage.key(i); + if (!predicate(key)) { + try { + localStorage.removeItem(key); + } catch (err) { + console.error("Failed to remove key", key, err); + } + } + } +} +type ClearResult = { + removed: string[]; + kept: string[]; + backupPreview: string[]; +}; + +export function clearExceptKeys(keysToKeep: string[] = []): ClearResult { + if (typeof window === "undefined" || !window.localStorage) { + return { removed: [], kept: [], backupPreview: [] }; + } + + const keepSet = new Set(keysToKeep.map(String)); + + // گرفتن snapshot از تمام کلیدها (با بررسی null) + const allKeys: string[] = []; + for (let i = 0; i < localStorage.length; i++) { + const k = localStorage.key(i); + if (k !== null) allKeys.push(k); + } + + // بکاپ (پیشنهاد می‌کنم فقط preview بگیریم یا در حافظه نگه داریم) + const backup: Record = {}; + allKeys.forEach((k) => { + backup[k] = localStorage.getItem(k); + }); + + const removed: string[] = []; + const kept: string[] = []; + + allKeys.forEach((key) => { + if (keepSet.has(key)) { + kept.push(key); + } else { + try { + localStorage.removeItem(key); + removed.push(key); + } catch (err) { + console.error("Failed to remove", key, err); + } + } + }); + + return { removed, kept, backupPreview: Object.keys(backup) }; +} diff --git a/src/apps/new-ui/Utils/selectedServiceStore.ts b/src/apps/new-ui/Utils/selectedServiceStore.ts new file mode 100644 index 00000000..d2f1838b --- /dev/null +++ b/src/apps/new-ui/Utils/selectedServiceStore.ts @@ -0,0 +1,60 @@ +// src/utils/selectedServiceStore.ts +const STORAGE_KEY = "serviceCost"; +const TITLE_KEY = "serviceTitle"; + +type Selected = { title: string; price: string }; + +const emitter = new EventTarget(); +let current: Selected | null = null; + +const toDigits = (s = "") => { + if (!s) return ""; + return s.replace(/,/g, "").replace(/[^\d]/g, ""); +}; + +export function setSelectedService(payload: Partial & { price?: any }) { + try { + const title = (payload.title ?? current?.title ?? "") as string; + const priceRaw = payload.price ?? current?.price ?? ""; + const price = String(priceRaw ?? ""); + current = { title, price }; + try { + localStorage.setItem(TITLE_KEY, title); + } catch {} + try { + localStorage.setItem(STORAGE_KEY, toDigits(price)); + } catch {} + // emit with detail in normalized form + emitter.dispatchEvent(new CustomEvent("selectedServiceChanged", { detail: { title, price: toDigits(price) } })); + // also emit legacy event for compatibility + setTimeout(() => { + try { + window.dispatchEvent(new CustomEvent("serviceSelected", { detail: { title, price: toDigits(price) } })); + } catch {} + }, 0); + } catch (err) { + console.error("selectedServiceStore.setSelectedService error:", err); + } +} + +export function getSelectedService(): Selected { + if (current) return current; + try { + const title = localStorage.getItem(TITLE_KEY) ?? ""; + const price = toDigits(localStorage.getItem(STORAGE_KEY) ?? ""); + current = { title, price }; + return current; + } catch { + return { title: "", price: "" }; + } +} + +export function onSelectedServiceChange(cb: (s: Selected) => void) { + const handler = (e: Event) => { + const ev = e as CustomEvent; + cb(ev.detail); + }; + emitter.addEventListener("selectedServiceChanged", handler); + // return unsubscribe + return () => emitter.removeEventListener("selectedServiceChanged", handler); +} diff --git a/src/apps/new-ui/components/AppointmentComponents/Services.tsx b/src/apps/new-ui/components/AppointmentComponents/Services.tsx index c7511f8b..fc430bf5 100644 --- a/src/apps/new-ui/components/AppointmentComponents/Services.tsx +++ b/src/apps/new-ui/components/AppointmentComponents/Services.tsx @@ -38,7 +38,7 @@ const Services = () => { }; }, [isAddServiceOpen]); - // When user selects a service via UI, dispatch 'serviceSelected' event (ServiceCost will apply it) + // When user selects a service via UI const handleServiceClick = (service: Service) => { const originalIndex = allServices.indexOf(service); if (service.name === selectedSlide?.name && originalIndex === selectedSlideIndex) { @@ -48,13 +48,13 @@ const Services = () => { setSelectedSlide(service); setSelectedSlideIndex(originalIndex >= 0 ? originalIndex : null); - // save title to localStorage (so tab/refresh retains selection) + // save title to localStorage const title = service.name ?? ""; try { localStorage.setItem(TITLE_KEY, title); } catch {} - // persist price to localStorage (so parents/components reading storage see the value) + // persist price to localStorage try { const priceStr = String(service.price ?? ""); localStorage.setItem(STORAGE_KEY, priceStr); @@ -64,7 +64,7 @@ const Services = () => { console.warn("writing price to storage failed:", err); } - // dispatch a dedicated event to signal that user explicitly selected a service + // dispatch event try { const ev = new CustomEvent("serviceSelected", { detail: { title, price: service.price ?? "" }, @@ -79,7 +79,7 @@ const Services = () => { return allServices.filter((service) => service.name.toLowerCase().includes(searchTerm.trim().toLowerCase())); }, [allServices, searchTerm]); - // keep selectedSlideIndex in sync with selectedSlide and allServices + // keep selectedSlideIndex in sync useEffect(() => { if (!allServices || allServices.length === 0) { setSelectedSlideIndex(null); @@ -90,82 +90,82 @@ const Services = () => { else setSelectedSlideIndex(null); }, [allServices, selectedSlide?.name]); - // initial selection when services list changes: - // priority: - // 1) editAppointmentService (if present) - // 2) saved serviceTitle in localStorage - // 3) default -> first service in the list - // - // Important: do NOT overwrite user's manual edited cost if EDITED_FLAG === "true" -useEffect(() => { - if (!allServices || allServices.length === 0) { - setSelectedSlide(null); - setSelectedSlideIndex(null); - return; - } - - const appointmentService = localStorage.getItem("editAppointmentService"); - if (appointmentService) { - const found = allServices.find((service) => service.name === appointmentService); - if (found) { - setSelectedSlide(found); - setSelectedSlideIndex(allServices.indexOf(found)); - try { localStorage.setItem(TITLE_KEY, found.name ?? ""); } catch {} - // persist price + dispatch on next tick so listeners are ready - if (localStorage.getItem(EDITED_FLAG) !== "true") { - try { - const priceStr = String(found.price ?? ""); - setTimeout(() => { - try { localStorage.setItem(STORAGE_KEY, priceStr); } catch {} - try { - window.dispatchEvent( - new CustomEvent("serviceSelected", { - detail: { title: found.name, price: found.price ?? "" }, - }), - ); - } catch {} - }, 0); - localStorage.removeItem(EDITED_FLAG); - } catch {} - } + // Initial selection logic + useEffect(() => { + if (!allServices || allServices.length === 0) { + setSelectedSlide(null); + setSelectedSlideIndex(null); return; } - } - const savedTitle = localStorage.getItem(TITLE_KEY); - if (savedTitle) { - const foundBySaved = allServices.find((service) => service.name === savedTitle); - if (foundBySaved) { - setSelectedSlide(foundBySaved); - setSelectedSlideIndex(allServices.indexOf(foundBySaved)); - try { localStorage.setItem(TITLE_KEY, foundBySaved.name ?? ""); } catch {} - if (localStorage.getItem(EDITED_FLAG) !== "true") { - try { - const priceStr = String(foundBySaved.price ?? ""); - setTimeout(() => { - try { localStorage.setItem(STORAGE_KEY, priceStr); } catch {} - try { - window.dispatchEvent( - new CustomEvent("serviceSelected", { - detail: { title: foundBySaved.name, price: foundBySaved.price ?? "" }, - }), - ); - } catch {} - }, 0); - localStorage.removeItem(EDITED_FLAG); - } catch {} + // 1. Check Edit Appointment Mode + const appointmentService = localStorage.getItem("editAppointmentService"); + if (appointmentService) { + const found = allServices.find((service) => service.name === appointmentService); + if (found) { + setSelectedSlide(found); + setSelectedSlideIndex(allServices.indexOf(found)); + try { localStorage.setItem(TITLE_KEY, found.name ?? ""); } catch {} + + // Only respect manual edits in Edit Mode + if (localStorage.getItem(EDITED_FLAG) !== "true") { + try { + const priceStr = String(found.price ?? ""); + setTimeout(() => { + try { localStorage.setItem(STORAGE_KEY, priceStr); } catch {} + try { + window.dispatchEvent( + new CustomEvent("serviceSelected", { + detail: { title: found.name, price: found.price ?? "" }, + }), + ); + } catch {} + }, 0); + localStorage.removeItem(EDITED_FLAG); + } catch {} + } + return; } - return; } - } - // default: first service - const first = allServices[0]; - if (first) { - setSelectedSlide(first); - setSelectedSlideIndex(0); - try { localStorage.setItem(TITLE_KEY, first.name ?? ""); } catch {} - if (localStorage.getItem(EDITED_FLAG) !== "true") { + // 2. Check Saved Title (Previous selection) + const savedTitle = localStorage.getItem(TITLE_KEY); + if (savedTitle) { + const foundBySaved = allServices.find((service) => service.name === savedTitle); + if (foundBySaved) { + setSelectedSlide(foundBySaved); + setSelectedSlideIndex(allServices.indexOf(foundBySaved)); + try { localStorage.setItem(TITLE_KEY, foundBySaved.name ?? ""); } catch {} + + if (localStorage.getItem(EDITED_FLAG) !== "true") { + try { + const priceStr = String(foundBySaved.price ?? ""); + setTimeout(() => { + try { localStorage.setItem(STORAGE_KEY, priceStr); } catch {} + try { + window.dispatchEvent( + new CustomEvent("serviceSelected", { + detail: { title: foundBySaved.name, price: foundBySaved.price ?? "" }, + }), + ); + } catch {} + }, 0); + localStorage.removeItem(EDITED_FLAG); + } catch {} + } + return; + } + } + + // 3. Default: First Service (Fix applied here) + const first = allServices[0]; + if (first) { + setSelectedSlide(first); + setSelectedSlideIndex(0); + try { localStorage.setItem(TITLE_KEY, first.name ?? ""); } catch {} + + // FIX: Always force price update for default fallback and CLEAR the edit flag. + // This ensures if there is only 1 service, the price is always set correctly. try { const priceStr = String(first.price ?? ""); setTimeout(() => { @@ -178,11 +178,11 @@ useEffect(() => { ); } catch {} }, 0); + // Important: We are falling back to default, so any "previous edit" is invalid. localStorage.removeItem(EDITED_FLAG); } catch {} } - } -}, [allServices]); + }, [allServices]); return (
@@ -194,7 +194,6 @@ useEffect(() => {
) : ( - // {/* Search Section */}
@@ -210,7 +209,6 @@ useEffect(() => {
)} - {/* Services Swiper */}
{ ); }; -export default Services; \ No newline at end of file +export default Services; diff --git a/src/apps/new-ui/pages/CheckTimeSlotCustomer/index.tsx b/src/apps/new-ui/pages/CheckTimeSlotCustomer/index.tsx index ba53ce40..421bd3d8 100644 --- a/src/apps/new-ui/pages/CheckTimeSlotCustomer/index.tsx +++ b/src/apps/new-ui/pages/CheckTimeSlotCustomer/index.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState, useMemo } from "react"; +import { useCallback, useEffect, useRef, useState, useMemo, useLayoutEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; import moment from "jalali-moment"; import toast from "react-hot-toast"; @@ -25,6 +25,7 @@ import GuidedOverlay from "@/apps/new-ui/components/GuidedOverlay/GuidedOverlay" import { useEndUserCreateReservation, useGetArtistFreeTimes } from "../../services/NewTest"; import AppointmentTimeClickable from "../../components/AppointmentComponents/AppointmentTimeClickable"; import { newAppointmentRoutes } from "../../routes"; +import { clearExceptKeys } from "../../Utils/removeLocalStorage"; type AppMap = Record; @@ -65,6 +66,10 @@ export default function CheckTimeSlotCustomer(): JSX.Element { const { data: customLink, isPending } = useGetCustomLink(customId); const navigate = useNavigate(); + useLayoutEffect(() => { + clearExceptKeys(["accounts", "userConfig"]); + }, []); + // customer const { data: customerData } = useGetCustomerForEndUser(+(customLink?.customer_id ?? 0), !!customLink?.customer_id); const [customerName, setCustomerName] = useState(undefined); diff --git a/src/apps/new-ui/pages/CheckTimeSlotGeneral/index.tsx b/src/apps/new-ui/pages/CheckTimeSlotGeneral/index.tsx index 61c78ccd..0142b6e5 100644 --- a/src/apps/new-ui/pages/CheckTimeSlotGeneral/index.tsx +++ b/src/apps/new-ui/pages/CheckTimeSlotGeneral/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useCallback, useState, useRef, useMemo } from "react"; +import { useEffect, useCallback, useState, useRef, useMemo, useLayoutEffect } from "react"; import toast from "react-hot-toast"; import { getJalaliDaysInMonth, @@ -25,6 +25,7 @@ import GuidedOverlay from "@/apps/new-ui/components/GuidedOverlay/GuidedOverlay" import SubmitPage from "./+components/SubmitPage"; import ServicesQA from "@/apps/new-ui/components/AppointmentComponents/ServicesQA"; import AppointmentTimeClickable from "../../components/AppointmentComponents/AppointmentTimeClickable"; +import { clearExceptKeys } from "../../Utils/removeLocalStorage"; type AppMap = Record; const STORAGE_KEY = "appointmentTimesMap"; @@ -74,6 +75,10 @@ const findFirstValidDay = ( export default function CheckTimeSlotGeneral() { const todayRef = useRef(getTodayJalali()); + useLayoutEffect(() => { + clearExceptKeys(["accounts","userConfig"]); + }, []); + const [selectedDateIso, setSelectedDateIso] = useState(() => { try { if (typeof window === "undefined") return null; diff --git a/src/apps/new-ui/pages/CreateTimeTable/+components/HolidayManagement.tsx b/src/apps/new-ui/pages/CreateTimeTable/+components/HolidayManagement.tsx index 72cc466f..5ed0b113 100644 --- a/src/apps/new-ui/pages/CreateTimeTable/+components/HolidayManagement.tsx +++ b/src/apps/new-ui/pages/CreateTimeTable/+components/HolidayManagement.tsx @@ -473,7 +473,6 @@ const HolidayManagement: React.FC = () => { if (currentStep === 2) { handleCustomerTimeChange(true); } - }; const [currentStepIndex, setCurrentStepIndex] = useState(0); @@ -536,7 +535,7 @@ const HolidayManagement: React.FC = () => { setIsGuideOpen(true); } }, []); - + useEffect(() => { if (isHolidaySelected) setStep([ @@ -577,7 +576,7 @@ const HolidayManagement: React.FC = () => { return (
{/* Guided overlay */} - {isGuideOpen && ( + {isGuideOpen && userInfo?.current_user.services && userInfo?.current_user.services.length !== 0 && ( { diff --git a/src/apps/new-ui/pages/PersonnelCheckTimeSlotCustomer/index.tsx b/src/apps/new-ui/pages/PersonnelCheckTimeSlotCustomer/index.tsx index 6ed62f83..9d67249a 100644 --- a/src/apps/new-ui/pages/PersonnelCheckTimeSlotCustomer/index.tsx +++ b/src/apps/new-ui/pages/PersonnelCheckTimeSlotCustomer/index.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import moment from "jalali-moment"; import toast from "react-hot-toast"; @@ -29,6 +29,7 @@ import { useCreateReserveEndUser, useGetMonthTimeslotsEndUser2 } from "../../ser import AppointmentTimeClickable from "../../components/AppointmentComponents/AppointmentTimeClickable"; import { newAppointmentRoutes } from "../../routes"; import GuidedOverlay from "../../components/GuidedOverlay/GuidedOverlay"; +import { clearExceptKeys } from "../../Utils/removeLocalStorage"; type AppMap = Record; @@ -69,6 +70,10 @@ export default function PersonnelCheckTimeSlotCustomer(): JSX.Element { const { data: customLink } = useSearchCustomLinkPersonel(customId); const navigate = useNavigate(); + useLayoutEffect(() => { + clearExceptKeys(["accounts", "userConfig"]); + }, []); + // customer const { data: customerData } = useGetCustomerForEndUser(+(customLink?.customer_id ?? 0), !!customLink?.customer_id); const [customerName, setCustomerName] = useState(undefined); diff --git a/src/apps/new-ui/pages/PersonnelCheckTimeSlotGeneral/index.tsx b/src/apps/new-ui/pages/PersonnelCheckTimeSlotGeneral/index.tsx index 69406734..2a9d8f3b 100644 --- a/src/apps/new-ui/pages/PersonnelCheckTimeSlotGeneral/index.tsx +++ b/src/apps/new-ui/pages/PersonnelCheckTimeSlotGeneral/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useCallback, useState, useRef, useMemo } from "react"; +import { useEffect, useCallback, useState, useRef, useMemo, useLayoutEffect } from "react"; import toast from "react-hot-toast"; import { getJalaliDaysInMonth, @@ -24,6 +24,7 @@ import "shepherd.js/dist/css/shepherd.css"; import { XIcon } from "lucide-react"; import AppointmentTimeClickable from "../../components/AppointmentComponents/AppointmentTimeClickable"; import GuidedOverlay from "@/apps/new-ui/components/GuidedOverlay/GuidedOverlay"; +import { clearExceptKeys } from "../../Utils/removeLocalStorage"; type AppMap = Record; const STORAGE_KEY = "appointmentTimesMap"; @@ -76,6 +77,10 @@ export default function PersonnelCheckTimeSlotGeneral() { const todayRef = useRef(getTodayJalali()); const { year: todayYear, month: todayMonth, day: todayDay } = todayRef.current; + useLayoutEffect(() => { + clearExceptKeys(["accounts", "userConfig"]); + }, []); + // ---- selected date (ISO gregorian) ---- const [selectedDateIso, setSelectedDateIso] = useState(() => { try { diff --git a/src/apps/new-ui/pages/ServicesMangement/+components/AddService.tsx b/src/apps/new-ui/pages/ServicesMangement/+components/AddService.tsx index e19b75d6..09fc0635 100644 --- a/src/apps/new-ui/pages/ServicesMangement/+components/AddService.tsx +++ b/src/apps/new-ui/pages/ServicesMangement/+components/AddService.tsx @@ -64,7 +64,7 @@ const AddService = () => { // قیمت اجباری تنها زمانی که user personnel نیست const priceIsValid = isUserAbilitiesPersonnel ? true : price > 0; - const btnEnable = addServiceTitle.trim() !== "" && !isPending && priceIsValid; + const btnEnable = addServiceTitle.trim() !== "" && !isPending && priceIsValid && time; // (اگر خواستی، می‌تونی isValidDuration(time) رو هم اضافه کنی) // ========= handlers =========