From 9f25c5f60ab6baa78d0070c4c23277282e134713 Mon Sep 17 00:00:00 2001 From: Gokul Date: Tue, 9 Jun 2026 11:25:29 +0530 Subject: [PATCH] udpates on the ui changesand api integration --- ..._All_Endpoints_With_Tables_And_Params.xlsx | Bin 0 -> 8436 bytes docs/01_ENDPOINT_CATALOG.md | 112 ++ docs/02_MOCK_DATA_GAP_ANALYSIS.md | 173 +++ docs/03_REQUIRED_BACKEND_APIS.md | 275 +++++ docs/BACKEND_API_REQUIREMENTS.md | 322 ++++++ docs/_endpoints_raw.txt | 105 ++ spec_bundle.js | 1009 +++++++++++++++++ src/App.tsx | 136 ++- src/components/AwaitingApi.tsx | 40 + src/components/DashboardView.tsx | 279 +++-- src/components/Header.tsx | 134 ++- src/components/InventoryView.tsx | 574 +++------- src/components/LoginView.tsx | 296 +++++ src/components/OperationsView.tsx | 80 +- src/components/OrdersDeliveriesView.tsx | 313 +---- src/components/ReportsView.tsx | 523 ++------- src/components/SettingsView.tsx | 382 ++----- src/components/StoreDetailView.tsx | 810 +++++-------- src/components/UserStorePage.tsx | 254 +++++ src/components/UserStoreSidebar.tsx | 62 + src/components/UsersPanel.tsx | 48 +- src/data.ts | 433 ------- src/index.css | 69 ++ src/services/auth.ts | 233 ++++ src/services/fiestaApi.ts | 137 +++ src/services/fiestaQueries.ts | 164 +++ 26 files changed, 4324 insertions(+), 2639 deletions(-) create mode 100644 Fiesta_All_Endpoints_With_Tables_And_Params.xlsx create mode 100644 docs/01_ENDPOINT_CATALOG.md create mode 100644 docs/02_MOCK_DATA_GAP_ANALYSIS.md create mode 100644 docs/03_REQUIRED_BACKEND_APIS.md create mode 100644 docs/BACKEND_API_REQUIREMENTS.md create mode 100644 docs/_endpoints_raw.txt create mode 100644 spec_bundle.js create mode 100644 src/components/AwaitingApi.tsx create mode 100644 src/components/LoginView.tsx create mode 100644 src/components/UserStorePage.tsx create mode 100644 src/components/UserStoreSidebar.tsx delete mode 100644 src/data.ts create mode 100644 src/services/auth.ts diff --git a/Fiesta_All_Endpoints_With_Tables_And_Params.xlsx b/Fiesta_All_Endpoints_With_Tables_And_Params.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f0b0cf4386aeb1c09459f16808153f9b20b406a9 GIT binary patch literal 8436 zcmZ{J1yCI8w)Nod?(PmjgS&*m-7UBT7=r5rhu|c*6I_D3ySoGl?iLs%1b%W(y?gG- zd;fHGcXidQ-Mv?D>2EJpB^X#-004jpKvC*9lpR!-Pky-?f7vl#c1vdqRaa*hHx4rw z7j{oa2jxj+lpao0_{~mrkH*iDGs=h$Vf zL6a$x?`wtB=zF(xUkTMPP?UWmMaJCsrW1|AQ4&mLfqRb97{$}b+8c3xw1n$KXdzJj zmkZ?ct|w#7|gW zGffP&ELdyguV^)rrVt;Z;|b`vho4DfRL;H-yurc|9Mj1^mrS8|S_)!R40J$0097hc zC+$_L7;7{aiAXz&UXx3>bijWssGvu~sg6X6FIgbA#kM<|MRFbw{+L~oZngmMIN(wZ zEpiGhu{9TtH9{fif~9#Q8bC0`-q-xV;Bf|cO*eRwGRKK}Q=R5!6$ZbaMQ*YOVj>`2*pwpKrcx>P$llY@=(PV-bE&6Ve{pQ` zh2!7kd^XIW!Gs3@G8g~=oELID9XQ-=tQ@WWK63r0=TzUoZAAdr|Ga9-(;DK4GQbzq zP>17Y>#1rq6@k3jd8ucEudGxZx{!=_giojqLL@>=z`&< z0Wk;7!cpDonl{+hA(v3j($vqG)kb_uQ%&F5gtBgzg69rzR5QjZ9|}iDg1$Mt?&{v5 z|8Zqq)N1ljh>SbPiIYT^GGM~Fcn7E-{#~=DuglI_Oxu2NdPY7lc-Suqu0;WoKZ}RR zjrLk7Q+L9{7t(i{9X+z*{>qVfbNkX$pkZ_-%7qkmQ>`_tC-d5&vp@o=F5h;_atX3h z8DCTyqoFc;>$h>7Zj*r=W1uo?|9)*YHe#S+$`h^QQYEanGGd@?%Kg}up5a%eeZe8V zjil`Mu{Sne{jT^dB|z83V_|FtCdHWP0hC0%OxC(4VR)f?CK!SBG|&&bU^_#U@=De< zGY$?Nz~49hM%A}Uq9Jm#Ct=1gZefzCUX>UzZ7AqQE|{wSTh*_d)Yjnw9`8&)p$Yq> z0NXOC;?vgj$;3yugPrW+#6@Mv370ljq|2W)24-OlPOouXg-ER>eJ3H1_(D4F$@6>U zW1z4#g?37{(d6V#Rl#GY527OHM6+1Z^_6-tNtRY7dx))N2TPz{0gW3+3^6nG zlbtFlbO91qN^a;~-9S0kCXQcY2jb91O!#e?bDD@wuCBrg_zqK+cq_wg&u!Y_Cqkj@ zG(@ZITYjo89#ksf#;a0Z*8T<0kG5ZFirwkQ4|s^XWvfU)VKy_u-cNA%8NA4(@g!u>)+AqLslc|a7vxp6 zv1t`OSS*sF=0tqNuJ!mq4ev_8rux_e)1JVYI;=;%a^6Hy)1i~`c+kW`JUUi_G5^bd zC!*r8I>|!?6w^-g-s!^r$};X%=spM@efz7)KXjhQfi?D4ZjL~42ZO#??2!8vLVlVa zQaf1NF1s}BmFO38Ze+O2W^&P8Z%<_Ylz}$Y%3vR;=jj#xp0c~(F2MkHzsbV$=4+AM znMQsZKkM$=W1~sb^nU(~zyH0-Dh-O`$J}lFMtJ3t? zXz=5dg1$=7Ha$j-Trl?`9atLBA&qLzTJc9>XGxMc9ctVtCNJ(*H8VB|8|)lb<+_Wq zPTmWf?AMK>@JKbfDjhW>b=1=fC|=i$xd6#WQD0jNCy+I~&mrUe2{H26p(*6lNR?_L zmh6CWY{~p4B#`wfz8QH|JQM;HtXAPNWVG zIQgVkF_evp1;j_embXYEC{oP(L8Q^K&!W($CD19u(}0~y*tWel_ztMigzeFQ0nOdq zDp=xe#bsS|wZVpp#A*<(hrOk2bUMGEo>A#d?eUQMzT5Qbm&>pm#_sEVlWQZXN`J`O z_JdR6Yxy@BUj0~5?lRCc$)xc31l&8SX9;oeI8ftB!_pVf!Inj&fu9~w+OJTXneZkm zLD)o9hWwJ3muNu#Z)Deit{>cBlN&Yp=E#14RN2dH)cY*w#dqdD= zRcIZ?cn^nFs=&Y7FETO^tIWKkrAp!+1vbKD(ujHHqsj$ikewyw#dpP4=g@2* zXs<});f%RHH}K`}0Fi~iJ)NUf_w>bnKaJ{y`ga34?SmYuVgLa3jsO7R-wouwv#Y(E zjg^(V8^>R#zq&|8=Bn$e0CuPe+-_8bgR+NZW})7oR>SUC3-f2s6U#krnTR+rvW%U= z2>IzOhj=ioue3pRX8bMjsm-IdT4IL%w%eDs}Jg`*a2ZDV}$$Tl{n4HL%Z>QvG5SUL^9 z_8iaOx$o6`E`R6^S#of@30vRo7hSrL%L-WCD86bmHd18t5T206{+d)JmSJ=gpm#kf zHh98G zGxIMCtoG=)M3#^A5l^^g9lu=oURzL^AcQdn$Y(wGf~2<};0Pqh4UG$id6cvYQVCdY zLcCu(Y>oN>m&)$O2VYfxFHpdsKZ?g=Ug~J7YQS+t-6ZeT{n!sjY<*#;xWQ8sbwmiS zu51GWTioh7LKgY5U)%`6m{(f+_31F>u{;8(07iAG(NOv`+nb$><5L}j=po^y^UnQ2 zkwy`Vpo}Y1DOld}5Mt*V%9;%$g8uCRwUyVjvp$$J>N?$l~3I-43T6|9tqtt`4 zb0gss4)+^7BKiZ7-A}bjDb#kF!2~tw%$LoaUrPZ>jb(vj>GgTONa^_C_hl_y6*8Y& zWP;GZsxbKWIxwGGR}jB1Du(G*^hP_-BxC;+VQH~%5awP+OT^B>4uT!ZAf=AO5s@A{ z{<81r9qQ+j5d2Wv0kNrtxN#xE{r&AE+DS&Mf#keMJFyT= z{B8kilS3=|R7XE0vY&|Dw0{T;mVLV|Y2SgwaL9<<6{XK2CNvqDh5SaGIYpj11fCD% zo>h)`im{1=au83yi;(q0Al&UHF|E5#;oh14X>j8!#Uo=ejioZD{Bjs4BZ)#+t%ylP zy)M^HsY5osy%v|HiC1ISUEnC}1Eo(n#;ycEbZ>%RxZl}SNz1uH;uN`@ir3UM3HXHO z;h}cFHiE%cWj=tOCBYY^;Z5)>TG4kZ=3vO~cDV#jlHS0tEGw@#irPlUVD-K!OA4-~ z#k?9WqPC0=1H$In2{F~vqr9wJPow!ph&vZ9KL^)Nvo|Q50-il?U0SP|gME$svd#KM zL;H0Xg2RmzPO#}bu+;L^P3MMkmFI>Q@#?91MT5%`I^tnE%Wpa__qVqF$3kw>j4HH; zsU|9N^Ycs(E|%FO-(8wWJ`hKfnuAdxXjq09c1i7kZV-;JT-(rw1HzJYV3qey5 z5|UDedt=rP9{TMa+LaM|E!UKJe>{H8isE;0_x)@sw~EC>$_EBkfuBi-q9u0O_iQ0Y zjf&G|XNvwHR+ry~7C^O-%==4bN?IgrH_#jXbQK)qYh*@}MMBBlf-xfuFOHI_dWEyR z{hg%cWc2n(z!w8`0!==Hg@?R^(FWcXl^q5#=meyR;A5fR^q54N3 zsEDNfp&p37JrfAc&_#Y-p)VB`J=GPs0eE|HG%2RYS8kZp2kp5BmFssYeJ}147SZOS zp<6r*jB%_@l%MNNVuVLR;4HL0r4Ikh!H$F&a$@Az`+c!6m5^AIRNbqWzaBgVLja4v z5+|akmb18_t`-VU6UJGhbDV(N40Dew2*SM-%H6$ugDvSJ2MY2(Q#5mNMRfCbKIr)@ zJYW^n72nR{61HKR#N|+~MAO8=!=Swf7L|t$*aNfE`>aH_!}z14`J*#Emb*plChq1Z zBL@6De=1BL;b>QRW(6DhxLiUQH8}pNw2P0cV%fkL{VjST||L zUmqx1B{adF83r{=1y^JzX8<$DgKznHsjswzmi0>uZg~PjrR2{mi5q*}`8>bF%Rb6O z%sphUEaayG4_4{g(gL}ZC^Bokq@DQ(+O19p&=*_2Ct-~J{+-JzkBj| zo{CfG2W{ifW=0TdY%C+G->jK@K1Ee4iXxGU=m!X!H)%Nm(_1Kb-f&uc@aOqTsZ;C%k8L5+{V>*DC*F!nMLEp0Ly>Fu?r+4_gFuNyG zX#rnHI)m*u*7X5n4Z{pYTQhlgX)9^a+^)aCvU#aiz`h}VDzc_H1U6E@*Em>+E);48 z3%XUMcF>exi{HD-Dvm7N7$rdSriU4Pjx6AA!!zS<2t`4}NJiB$Yj0skcc;@X!Oq(I zHv8hK-(HtI`Wbx9cn#`z9&!VRD{~~aM}JytlgBoI3uM`X+;H1$&_BhZY|(_I(SYqt zwp=HpN&zi1sjGBVJ(=NU^k!Os%IJJ%m!27cYmhuA-xopIHV-Mvao%gm^uBlzBp{HZ z9WidS*&;*rlDL*s!)uI~?CYii-yJ2YMwS&?N}eo~A@@|@hYz$ug6)UBu<-PQxNjDM zJ+y!Mdix@2GW#3hAI}=9Y z4kfbY`bAYjKOA}Km6e|_sqPX&>4`{{r8hXjt8)k^Jb2E~)j4x1xZP#NA(HU}&$=uv z=~gONBIh(YXt0H=-GIXP~cD1mA?@Kwygn4h{tQ2?TV+>6?)>B_EFSRmYRsXEmfo^5& z*g+;+xt1Xt2009YPQLZ)O`3$GWmMx5-XOIh`x&W`7?aVg`y{np*)^zZ{M1t5TDbEw z!xO5D=%gtJqLu?OF-L@)L@(sfm`wVQ!Yn@_$fGS*3*(Bp+hB?Pes!Cm;2f37#r3h} zh>DnMR!*%Dh@<3rQ@)!yCny-;ti}$HcpTAUe-JwHj{0Yu_ZV~w@5iIL(X)A>pJiGF zvFWeq;k6hvsb3}Wez#cwN@tWr!Gs54r^44sLC{YP^;DQWUI{3_&OR=6>iTC3;%)E-7P$xFxn} znX76RQtd^7&e6EzhcED4Dnk*Rw6 zS!yQkF3GljoL`qa1d(_rBctXAwqT%R$CeL1AxofaEVaEyG$#Z}o-$UzdTEF-3JRy5 z=C(_r??A46si=D90*`QOjJ^6=PTpL{rkc-sX<$c`A$TvN;eR}{5QpHQ;eM3C>}!73GqF-UNCyh$GzgTY)SbA z6y3NGkK#~|;@BTbGD|1MKo@i$P~@R<{~WO=xk)g@eKyFcG7zm9XlC~{Tr#^O72w9`e!to<1w`uvey5+lqR)5T ztyqh2*TtV1c$OA&7xc5=oC`cmf}Y*l-Kk?=O>zAqSN~~YlRHS@>0aevCZeGz<~T;5 z?Cnf)Uj_KQUUqE>r=|YWrZSo>kZA^WOLw;yv~%-KG(6Dog5u46%v*s_vqiex{Bi37zf zg|PPg*q3qnUV7lO!~jtbJ6e=X6CP7a>wD3K=Bkg=$1L-8xLHGprxAS9SOnJa1lEXS z#_NZHVlF!vVlKqwtG=6GV0Gp~F|84s-J4P-*NBCg;r;raTo8>6yNR#TyDO4xvB|X| z7N994kO}AU7mArSf=OaV!-LB60{i+J%eR=$vQ)-5#&-5sM+hwV9ua2bsc_fg5FgeD zXd$8{$I|JhbCvz7*`0`T+!zBk1=#4kqsT$NTfla0Am4?&cS%fsp1a{=7SUt6+MP~z z&75;@RpTN9i1)eqUslHf>B_Btt_ilN&rxQ;~*)A@n+BcNsx z`|9i-yx9Jneyb?BzU2LO_?-fLyy`NdA*Cv&aj7P=yc0#}L}o!gF3+5h9O7N`N$J?8 zu~RvS_TKcJJcs8g_Poh`q4;Z%YN*Tp&Ie_0%d)d$WAZYI2@n$#J3b>Ehq>!V_o+q1 zqP4@bk+_SDks$57wudViMN}2pP>3TD5&q`zkX!FdZ^`gh@-9>qiBuNNYBXyuy3PtIq4srX(ol?ZJ;?Y;>HSi6OnpZ9_bS}?NB%dpm-#jX2>?L*dll~H z?&Vokq#815M6s}aIOmo>#S~2{z%muLywnnZJu8&{S2zq=i z(_{22Q@$7@&1@#Ip8Z*dJ!wrP+-hU>;OGJA_?fZ)>yq`=x!5w0P+b4`)oo6T#`=5U zMUh;B_Pt#VquY4lum=gxK|4g`^-A}hW5dwZT2cMm2G*}Of%%3gkdb-5vgQN?hF-nO z!WP*d$Y^q9~q3czjf$ z83;Ed9Fj~b$t+!5A6pDXEP1GeDTlgSWSd%r@@*T{@@~XkuG|NT8;xRfZnZSBrgu;6fX3HHJnJUb;&HI<%&RTxG;htdLriISXlXJI z+BO-;cSRap26J0jE@t#(sQw66=80#`$+U6?b4{mX+FE)+`ve?4rUG<+JcjX-O+_7j zEg7{GO}S&C&l1Wv6|9%35ZT>ORAzM9hgRd+*&_a(ZIPU}57VKl$usHlT8g*C@$MUO zYFdZ38t>vHl!I2tqO)T|UMKJ2!U2;T)U zxvluAKtV%P3E?kHbzA-UCMfv^x{tOK@sgEutmM35Gvd;#7E;yvtfJ!VL~k40E%A%p z3UtB^7c&b*RykB8oCB+b-n^5vl~>|HzZjnh;J*EV$}6+0NRw

^ZypaIJkdjqlp~*&4Moaoq638Z}2e2i9g`qj%KusUOg+_f$Hth$0Wxny5*464p z+j^68dMe$E{^HipMtg7f@U6GDvkpG_dJ&jA*~P!jDysR?z3M522Aiqbw;m}eT2NzF zZB-7{*Xo{T^>xkwbmo6UA30R19AWE^|`5QPq>de<3{u0Ir^I|uAD)X zq~_r_*!Du5nA;zMbsO0}WsHtn5}pLYMTuQE@Z8(p)>!wQiIo!%kF#oYBMT~aP9GcG zctRVItFqKdGIS}iT#U`}5u#^C7s*$dUyDTVt8QgHYtU%n;a3;r-C$ZC#CL<>rOIm} z=#dtroU{?u9Il%52HBHEzp{sc^A;)}wgis?7k5ov-L)k@K#lO@MUB`i^@k>&9e|1& z-zWMw=7Y`@nr|-@8%RT9v#&2;{!KD1d3s*O3%PeML=*o_^4|gV-&FqRc_x5G?eY>`;vvCKOAoR=Z|B;^iTv-K7DRV#3T z!P#bXP$FZ=q=-kn^QOn9fv;PAYxGS@-WP77Nahq5eafw2N=I95ziJg=-M$wA|E)~r z_%>4I2C9pv`_msoQ>!?y1fmxQCt?0p-3+9ho!qUQ+)XsST&&!Ten(S9qB5|T6Z6G8 zD+4-qR^6N;5>pf-7bpuA;zPT%fN>BWG+WOuf-K*rE20Mj0-K2 z4=Tik^t-%Qwnm7gR*B(+zO-+r5L-Z()WA?$A5Xh;Dbr_hMo+dbKX$)G9vV?b#uBW7 z4H(R%8D7(}q>;BQs`8|&y*c?Q0W=8dh#%kng=)*c6J)NtH+knXK=4d5af#J))+tug zwg4m!*o*ouW*qRsBos6*%>Q4Zeu WD#5*|-2ed6%O?6#$8*SkU;RHz&^+4! literal 0 HcmV?d00001 diff --git a/docs/01_ENDPOINT_CATALOG.md b/docs/01_ENDPOINT_CATALOG.md new file mode 100644 index 0000000..b580e71 --- /dev/null +++ b/docs/01_ENDPOINT_CATALOG.md @@ -0,0 +1,112 @@ +# Fiesta / Workolik Endpoint Catalog + +Source: `Fiesta_All_Endpoints_With_Tables_And_Params.xlsx` (103 endpoints) cross-referenced +with the REST clients already in this repo (`src/services/api.ts` β†’ Hasura `/hasura/*`, +`src/services/fiestaApi.ts` β†’ Fiesta `/fiesta/*`). + +Legend for **Client** column: +- βœ… **wired** β€” a function + TanStack hook already exists in this repo. +- 🟑 **available** β€” endpoint exists on the backend (in the sheet) but we have **no client yet**; safe to add. +- πŸ”΄ **REVIEW_REQUIRED** β€” the sheet marks the table as `REVIEW_REQUIRED` (mostly POST/PUT auth & mutation routes); shape must be confirmed with backend before wiring. + +> The sheet only documents GET read tables + a handful of mutations. It does **not** +> contain any analytics/aggregation, time-series, alerting, telemetry, or audit-log +> endpoints. Those gaps are listed in `03_REQUIRED_BACKEND_APIS.md`. + +--- + +## App / Config +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Utils | GET | app_types | tag | βœ… `getAppTypes` | +| Resolve subcategories | GET | app_subcategory | moduleid, categoryid | βœ… `getSubcategory` | +| System active geofence | GET | app_location | applocationid | βœ… `getAppLocations` | +| Global system categories | GET | app_category | None | βœ… `getProductCategories`* | +| Global payment & geofence configs | GET | app_config | configid | 🟑 available | +| App location config | GET | app_locationconfig | applocationid | βœ… `getAppLocationConfig` | + +## Users / Auth +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Users list | GET | users | roleid, tenantid, pageno, pagesize, keyword | βœ… `getAllUsers` | +| User profile by id | GET | users | userid | βœ… `getUserById` | +| Tenant Web Panel Login | POST | REVIEW_REQUIRED | β€” | βœ… `loginRequest` (weblogin) | +| General Application Login | POST | REVIEW_REQUIRED | authname, password, configid, userfcmtoken | βœ… `loginRequest` (applogin) | +| Register Web Staff | POST | REVIEW_REQUIRED | β€” | βœ… `createUser` | +| Update Web Staff | PUT | REVIEW_REQUIRED | β€” | βœ… `updateUser` | +| App roles | GET | (approles) | configid | βœ… `getAppRoles` | + +## Orders +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Orders board | GET | orders | tenantid, locationid, status, pageno, pagesize | βœ… `getOrders` | +| System Admin orders board | GET | orders | applocationid, status, pageno, pagesize | 🟑 available | +| Order dashboard stats summary | GET | orders | tenantid, fromdate, todate | βœ… `getOrderSummary` | +| Annual orders insights | GET | orders | tenantid | βœ… `getOrderInsight` | +| Location orders summary | GET | deliveries | tenantid | βœ… `getLocationSummary` | +| **Order detailed lines** | GET | orderdetails | orderheaderid | 🟑 **available β€” not wired (needed for line items)** | +| Customer order history | GET | orders | customerid, status, pageno, pagesize | 🟑 available | +| Create Web Order | POST | orders+orderdetails | β€” | πŸ”΄ REVIEW_REQUIRED | +| Update Order Status | PUT | orders | β€” | πŸ”΄ REVIEW_REQUIRED | + +## Deliveries +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Deliveries board (master) | GET | deliveries | tenantid, fromdate, todate | βœ… `getDeliveries` | +| Deliveries summary | GET | deliveries | tenantid, applocationid, fromdate, todate | βœ… `getDeliverySummary` | +| Daily delivery insights | GET | deliveries | tenantid | βœ… `getDeliveryInsight` | +| Location deliveries summary | GET | deliveries | tenantid | 🟑 available | +| **Deliveries financial report summary** | GET | deliveries | tenantid, partnerid, userid, applocationid, fromdate, todate | 🟑 **available β€” needed for Reports revenue** | +| **Fleet rider summary metrics** | GET | partneruser | applocationid, partnerid, tenantid, fromdate, todate | 🟑 **available β€” needed for fleet KPIs** | +| Assign Rider / dispatch | POST | deliveries+deliverydetails | β€” | πŸ”΄ REVIEW_REQUIRED | +| Update pickup / delivered | PUT | deliveries | β€” | πŸ”΄ REVIEW_REQUIRED | + +## Partners / Riders +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Active riders | GET | partneruser | partnerid, applocationid, userid, tenantid | βœ… `getRiders` | +| Partner profiles | GET | partneruser | partnerid, applocationid, userid | 🟑 available | +| Rider shifts | GET | partneruser | applocationid | βœ… `getRiderShifts` | +| Rider log sheet | GET | riderlogs | partnerid, applocationid, fromdate, todate | 🟑 available | +| Partners | GET | orders | partnerid, status, pageno, pagesize | βœ… `getPartners` | + +## Tenants / Stores +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| All active tenants | GET | tenants | applocationid, status, pageno, pagesize | βœ… `getAllTenants` | +| Tenant detail profile | GET | tenants | tenantid, locationid | βœ… `getTenantInfo` | +| Tenant outlet locations | GET | tenantlocations | tenantid | βœ… `getTenantLocations` | +| Tenant store staff | GET | tenantstaffs | tenantid | 🟑 available | +| Logistics pricing slabs | GET | tenantpricing | tenantid, applocationid | 🟑 available | +| Delivery time slots config | GET | tenantslot | None | 🟑 available | +| Onboard tenant / store / location | POST/PUT | REVIEW_REQUIRED | β€” | πŸ”΄ REVIEW_REQUIRED | + +## Customers +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Customers | GET | customers | customerid, contactno | βœ… `getCustomersByTenant`* | +| Merchant customers list | GET | tenantcustomers | tenantid, locationid, pageno, pagesize, keyword | βœ… `getTenantCustomers` | +| Customer order history | GET | orders | customerid, status, pageno, pagesize | 🟑 available | +| Register / update customer | POST/PUT | REVIEW_REQUIRED | β€” | πŸ”΄ REVIEW_REQUIRED | + +## Products / Stock +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Stock counts | GET | products | tenantid, categoryid, subcategoryid, approve | βœ… `getProductsCount` | +| Global categories | GET | productcategories | None | βœ… `getProductCategories` | +| Product subcategories | GET | productsubcategories | categoryid, tenantid | βœ… `getProductSubcategories` | +| Product variants | GET | productvariants | tenantid, subcategoryid | βœ… `getProductVariants` | +| Master catalog listings | GET | products | tenantid, locationid, subcategoryid, keyword, pageno, pagesize | 🟑 available | +| **Live stocks catalog** | GET | productstocks | tenantid, locationid | 🟑 **available β€” real stock levels** | +| Stock statement ledger | GET | product_stock_statement | tenantid, locationid, subcategoryid, pageno, pagesize, keyword | βœ… `getStockStatement` | +| **Outlet geofenced inventory** | GET | productlocations | tenantid, locationid, subcategoryid, pageno, pagesize | 🟑 **available β€” per-outlet inventory** | +| Create / update / delete product | POST/PUT/DELETE | REVIEW_REQUIRED | β€” | πŸ”΄ REVIEW_REQUIRED | +| Add multi-product stock entry | POST | REVIEW_REQUIRED | β€” | πŸ”΄ REVIEW_REQUIRED | + +## Invoice / Payments +| API | Method | Table | Params | Client | +|---|---|---|---|---| +| Invoice insight | GET | invoice_insight | tenantid | βœ… `getInvoiceInsight` | +| Payments | GET | paymentrequests | partnerid, status | 🟑 available | + +\* Close match; verify exact route/shape against backend. diff --git a/docs/02_MOCK_DATA_GAP_ANALYSIS.md b/docs/02_MOCK_DATA_GAP_ANALYSIS.md new file mode 100644 index 0000000..fa2b90d --- /dev/null +++ b/docs/02_MOCK_DATA_GAP_ANALYSIS.md @@ -0,0 +1,173 @@ +# Mock-Data β†’ Live-API Gap Analysis + +Goal: remove every hardcoded / mock value in `src/` and back it with a live API before staging. + +Each row is classified: +- **WIRE** β€” a live endpoint already exists (βœ… or 🟑 in `01_ENDPOINT_CATALOG.md`); just connect it / remove the mock fallback. +- **DERIVE** β€” no dedicated endpoint, but the value is computable client-side from data we already fetch (e.g. period-over-period deltas by querying two date ranges). No backend work needed. +- **NEW API** β€” no endpoint exists and the value cannot be derived; backend must build it. Spec'd in `03_REQUIRED_BACKEND_APIS.md` under the referenced **[Rxx]** id. + +Central mock source file to delete once empty: **`src/data.ts`**. + +--- + +## 1. DashboardView.tsx *(mostly live already)* +| UI element | Current source | Class | Target | +|---|---|---|---| +| Active Outlets / Total / % | live `useTenantLocations` + `useOrderSummary` | OK | β€” | +| Region fulfilment %, delivered/total | live `useOrderSummary` | OK | β€” | +| Monthly Revenue, Monthly Profit | live `useInvoiceInsight` | OK | β€” | +| Per-location orders / dispatched / fulfilled % | live `useFiestaLocationSummary` | OK | β€” | +| KPI card icons / gradients / static subtext labels | hardcoded | keep | cosmetic, not data | +| Banner title "Executive Command Center", "Live Core" | hardcoded | keep | cosmetic | + +**Dashboard is ~clean.** Only cosmetic strings remain. + +--- + +## 2. ReportsView.tsx *(heaviest mock load)* +| UI element | Current source | Class | Target | +|---|---|---|---| +| Orders KPI value / delivered / cancelled | live `useFiestaOrderSummary` | OK | β€” | +| KPI trend deltas `+12.5%`, `+14.8%`, `-1.2%`, `+8.4%` | hardcoded | **DERIVE** | query current + previous period summary, compute % change | +| Revenue value `= delivered Γ— 355` | hardcoded multiplier | **NEW API** | **[R1] revenue summary** (real money, not a guess) | +| Active SKU count | live stock length | OK | β€” | +| `CHART_DATA_YTD` (12-mo orders/revenue/cancelled/skus) | hardcoded | **NEW API** | **[R2] order+revenue time-series** (orders partly via `getOrderInsight`; revenue & skus need [R1]/[R2]) | +| `getDynamicChartData` month/12M/all-time series | hardcoded | **NEW API** | **[R2]** with `granularity=day|month|year` | +| Region scaling multipliers (0.42 / 0.60 / 0.75…) | hardcoded fudge | **NEW API** | **[R2]** filtered by region/location β€” remove multipliers | +| Monthly order heatmap β€” Coimbatore rows | live `useFiestaOrderInsight` | OK | β€” | +| Monthly order heatmap β€” Chennai/Bangalore stub rows | hardcoded | **WIRE** | `getOrderInsight` returns all tenant locations; remove stubs | +| `MONTH_LABELS`, `MONTH_KEYS` | hardcoded | keep | static axis labels | +| Top-nodes leaderboard names / order counts | live (location summary) | OK | β€” | +| Leaderboard **revenue** column | derived from order count | **NEW API** | **[R1]** revenue-per-location | +| Product matrix rows | live `useFiestaStockStatement`β†’`stockRowToProduct` | OK | β€” | +| `unitsSold`/`revenue` per product (mapper uses `debit`Γ—`retailprice`) | approximated | **NEW API** | **[R3] product sales analytics** (true units sold + revenue) | +| Expanded-row stock units (142/42/6), bar widths, hub split 60/40 | hardcoded | **WIRE/NEW** | per-outlet via `productlocations` 🟑; hub split = real `productstocks` | +| Warehouse Bin `BIN-C…`, "Last Audited" date, barcode bars | hardcoded | **NEW API** | **[R3]** product meta (bin, last-audit) β€” or drop if not tracked | +| Export progress modal | simulated | keep | client UX only | + +--- + +## 3. InventoryView.tsx +| UI element | Current source | Class | Target | +|---|---|---|---| +| Banner active-outlets count | live `useFiestaTenantLocations` | OK | β€” | +| Banner total on-hand volume | live `useFiestaStoresStock` | OK | β€” | +| Global catalog grid | live stock β†’ `stockRowToProduct` | OK | β€” | +| Optimal/Low/Critical hub counts | derived from live stock + thresholds | OK | thresholds are business rules, keep | +| Per-store SKU lists, capacity bars | live `useFiestaStoresStock` | OK | β€” but prefer real capacity ([R3]) | +| `initialImportLogs` (Live Sync Audit Stream) | mock `data.ts` | **NEW API** | **[R4] import/sync audit log** | +| CSV import default template string | hardcoded | keep | UX template | +| Nilgiris Dairy / Coimbatore Heritage presets | hardcoded | **WIRE** | catalog presets β†’ `getAllTenants`/master catalog 🟑, or **NEW [R5]** | +| Brand Design Studio (theme, colors, bag label, eco-seal) | hardcoded local state | **NEW API** | **[R6] merchant branding config** (GET+PUT) | +| Add-Product modal category list | hardcoded | **WIRE** | `getProductCategories` / `getProductSubcategories` | +| Add-Product modal default price/stock | hardcoded | keep | form defaults | + +--- + +## 4. OperationsView.tsx +| UI element | Current source | Class | Target | +|---|---|---|---| +| Inventory value, low-stock count, SKU count | live `useFiestaStockStatement` | OK | β€” | +| Fulfillment Health `98.4%` | hardcoded | **DERIVE** | from order/delivery summary | +| Forecast Efficiency `92%`, Cost savings `β‚Ή1.9L/week` | hardcoded | **NEW API** | **[R7] forecasting/insights** (or remove until modelled) | +| Catalogue table rows | live `stockRowToProduct` | OK | β€” | +| "Global Inventory Count 4,200 nodes" | hardcoded | **WIRE** | `getProductsCount` | +| Catalogue verification toggle | local state only | **NEW API** | product update PUT πŸ”΄ (REVIEW_REQUIRED) | +| Import logs table | mock `data.ts` | **NEW API** | **[R4]** (same as Inventory) | +| Schema-validator messages ("14 duplicate SKUs") | hardcoded | **NEW API** | **[R4]** import validation result | +| Add-SKU / Transfer-Stock modals | local state mutation | **NEW API** | stock entry POST πŸ”΄ + **[R8] stock transfer** | + +--- + +## 5. OrdersDeliveriesView.tsx +| UI element | Current source | Class | Target | +|---|---|---|---| +| KPI tiles (deliveries in range, pending, completed, fleet) | live `useFiestaDeliveries` | OK | β€” | +| Date presets / range | client state | OK | β€” | +| Order list rows | live `deliveryRowToOrder` | OK | β€” | +| **Order line items** (`items: []` always empty) | empty / itemCount only | **WIRE** | **`orderdetails?orderheaderid=`** 🟑 (exists!) | +| "Create Simulated Order" + MOCK_NAMES/STREETS/ITEMS | hardcoded generator | **NEW API** | replace with real Create-Order POST πŸ”΄, or remove button | +| Rider cards | live `useFiestaRiders` | OK | β€” | +| Rider `rating 4.7` | hardcoded in mapper | **NEW API** | **[R9] rider telemetry/rating** | +| Rider avatars | rotated stock photos | **WIRE** | user photo field if present, else keep placeholder | +| GPS route SVG, "9 MINS", "1.2 km left", "GPS ACTIVE" | hardcoded | **NEW API** | **[R9]** live rider GPS/ETA | +| Status-progression buttons (pack/dispatch/deliver) | local state | **NEW API** | order/delivery status PUT πŸ”΄ (REVIEW_REQUIRED) | +| Assign-rider action | local state | **NEW API** | assign-rider POST πŸ”΄ (REVIEW_REQUIRED) | + +--- + +## 6. StoreDetailView.tsx +| UI element | Current source | Class | Target | +|---|---|---|---| +| Inventory tab list | live `useFiestaStockStatement` + mock fallback | **WIRE** | remove hardcoded fallback array | +| Customers tab list | live `useFiestaTenantCustomers` + mock fallback | **WIRE** | remove hardcoded fallback array | +| `intervalSlots` dispatch pipeline (morning rush %, etc.) | computed from `store.deliveries`Γ—% | **NEW API** | **[R10] intraday dispatch buckets** | +| `pastDaysLog` 7-day ledger | computed Γ—multipliers | **NEW API** | **[R2]** daily series per location | +| KPI cards (OTIF 98.2%, est revenue, dispatches, active fleet) | hardcoded/derived | **WIRE/NEW** | OTIF & revenue need [R1]; fleet via `getRiders` | +| `activeRiders` (battery, lastPing) | hardcoded | **NEW API** | **[R9]** rider telemetry | +| Customer CRM order history (3 orders) | hardcoded | **WIRE** | `orders?customerid=` 🟑 | +| Customer CRM metrics (CSAT 5.0) | hardcoded | **NEW API** | **[R11] customer analytics** (CSAT/AOV/retention) | +| Customer search metrics (retention 88.4%, AOV β‚Ή1,580, CSAT 4.9) | hardcoded | **NEW API** | **[R11]** | +| `GLOBAL_CATALOGUE_ITEMS` modal | hardcoded | **WIRE** | master catalog listings 🟑 | +| `resolveMetadata` price/image keyword map | hardcoded | **NEW API** | **[R3]** product image/price from catalog | +| Store cover images | hardcoded array | keep | cosmetic asset set | +| `operationalAlerts` (filtered by store) | mock `data.ts` | **NEW API** | **[R12] operational alerts** | +| CSV import simulation, Global-catalogue add | local mutation | **NEW API** | stock entry POST πŸ”΄ | + +--- + +## 7. SettingsView.tsx +| UI element | Current source | Class | Target | +|---|---|---|---| +| Merchant ID card / registration info | live `useFiestaAllTenants` | OK | β€” | +| Outlets tab cards | live `useFiestaTenantLocations` | OK | β€” | +| `LOCAL_OUTLETS_DATA` fallback | hardcoded | **WIRE** | remove fallback once locations confirmed live | +| `DEFAULTS` settings (min order, delivery charge, prep mins, tax, COD…) | hardcoded + localStorage | **NEW API** | **[R6] merchant settings** GET+PUT (some fields exist on tenant: minorder, paymenttype) | +| Role dropdown options | hardcoded `[1,2,3,4,6]` | **WIRE** | `getAppRoles` | + +--- + +## 8. UsersPanel.tsx +| UI element | Current source | Class | Target | +|---|---|---|---| +| User directory | live `useFiestaUsers` | OK | β€” | +| Create user | live `useFiestaCreateUser` | OK | β€” | +| `USER_AVATARS` rotation | hardcoded | keep/WIRE | use user photo field if API has one | +| `ROLE_THEMES` styling | hardcoded | keep | cosmetic | +| Add-user modal role list | hardcoded | **WIRE** | `getAppRoles` | + +--- + +## 9. App.tsx / Header / Sidebar / UserPage +| UI element | Current source | Class | Target | +|---|---|---|---| +| Store registry cards | live `useFiestaTenantLocations` + `useFiestaLocationSummary` | OK | β€” | +| `STORE_COVERS` images | hardcoded (hash-picked) | keep | cosmetic | +| Add-store modal | local; needs onboard POST | **NEW API** | tenant/location onboard πŸ”΄ (REVIEW_REQUIRED) | +| Scheduled-reports calendar (3 events) | hardcoded | **NEW API** | **[R13] scheduled reports** (or drop feature) | +| Header/UserPage profile | live `authUser` | OK | β€” | +| Sidebar nav items | hardcoded | keep | static nav config | + +--- + +## Summary of backend work required +| Id | New API | Blocks | +|---|---|---| +| **[R1]** | Revenue summary (tenant + per-location, period) | Reports revenue KPI, leaderboard revenue, OTIF revenue, Dashboard cross-check | +| **[R2]** | Orders/revenue time-series (day/month/year, by region) | Reports main chart, 7-day ledger | +| **[R3]** | Product sales analytics + product meta (units sold, revenue, bin, image) | Product matrix, catalogue metadata | +| **[R4]** | Import / sync audit log + validation | Inventory & Operations import tabs | +| **[R5]** | Catalog presets (optional) | Inventory presets | +| **[R6]** | Merchant settings + branding config (GET/PUT) | Settings, Brand Studio | +| **[R7]** | Forecast / efficiency insights (optional) | Operations forecast panel | +| **[R8]** | Stock transfer (POST) | Operations transfer modal | +| **[R9]** | Rider telemetry (rating, battery, GPS, ETA) | Orders fleet, GPS tracker, StoreDetail riders | +| **[R10]** | Intraday dispatch buckets | StoreDetail dispatch pipeline | +| **[R11]** | Customer analytics (CSAT/AOV/retention) | StoreDetail CRM metrics | +| **[R12]** | Operational alerts feed | StoreDetail / dashboard alerts | +| **[R13]** | Scheduled reports (optional) | Reports calendar | + +Plus mutation routes already in the sheet but marked πŸ”΄ REVIEW_REQUIRED (order create/status, +delivery assign/status, product create/update, tenant onboard, stock entry) β€” backend must +confirm request/response before wiring. diff --git a/docs/03_REQUIRED_BACKEND_APIS.md b/docs/03_REQUIRED_BACKEND_APIS.md new file mode 100644 index 0000000..0d2a673 --- /dev/null +++ b/docs/03_REQUIRED_BACKEND_APIS.md @@ -0,0 +1,275 @@ +# Required Backend APIs (to retire all mock data) + +These endpoints do **not** exist in `Fiesta_All_Endpoints_With_Tables_And_Params.xlsx` and the +values cannot be derived client-side. Each spec gives the **request** (params/body) and the +**exact response JSON** the frontend needs. All responses follow the existing Fiesta envelope: + +```json +{ "code": 200, "status": true, "message": "OK", "details": } +``` + +`details` is the `` documented per endpoint. Money is in INR (paise-free rupees, +2-dp numbers). Dates are `YYYY-MM-DD`; timestamps ISO-8601. + +Grouped as the request asked: **Overall (executive) analysis**, **Store-wise analysis**, +**Reports**, then supporting operational feeds. + +--- + +## A. OVERALL / EXECUTIVE ANALYSIS + +### [R1] Revenue summary β€” `GET /orders/getrevenuesummary` +Real money totals (today the app fakes revenue as `delivered Γ— 355`). + +**Request** +| param | type | required | notes | +|---|---|---|---| +| tenantid | int | βœ“ | | +| locationid | int | | omit = all outlets (overall); set = store-wise | +| fromdate | date | βœ“ | | +| todate | date | βœ“ | | + +**Response `details`** (single object) +```json +{ + "tenantid": 1087, + "grossrevenue": 1248302.00, + "netrevenue": 1180500.00, + "profit": 354216.00, + "marginpct": 28.4, + "ordercount": 4921, + "deliveredcount": 4102, + "cancelledcount": 142, + "avgordervalue": 1580.00, + "prev_grossrevenue": 1090000.00, + "prev_ordercount": 4370 +} +``` +`prev_*` = same metric for the immediately preceding equal-length window, so the UI can show +the `+14.2%` deltas without a second call. (If omitted, the frontend will issue a second +range query to derive deltas β€” see [R2].) + +--- + +### [R2] Orders/revenue time-series β€” `GET /orders/gettimeseries` +Powers the Reports main chart (Orders / Revenue / Cancelled / SKUs) and the StoreDetail 7-day ledger. + +**Request** +| param | type | required | notes | +|---|---|---|---| +| tenantid | int | βœ“ | | +| locationid | int | | omit = overall | +| granularity | enum | βœ“ | `day` \| `month` \| `year` | +| fromdate | date | βœ“ | | +| todate | date | βœ“ | | + +**Response `details`** (array, one bucket per period) +```json +[ + { "label": "2026-06-01", "orders": 312, "revenue": 442800.00, + "cancelled": 9, "delivered": 298, "activeskus": 72 } +] +``` +`label` is the bucket key (`YYYY-MM-DD` for day, `YYYY-MM` for month, `YYYY` for year). +This removes all hardcoded `CHART_DATA_YTD` / `getDynamicChartData` arrays **and** the +region-scaling multipliers (filter by `locationid` instead). + +--- + +### [R12] Operational alerts β€” `GET /alerts/getalerts` +Replaces `operationalAlerts` in `data.ts` (stock-critical, latency, rebalance, etc.). + +**Request**: `tenantid` (βœ“), `locationid` (optional), `status` (`open|all`), `pageno`, `pagesize`. + +**Response `details`** (array) +```json +[ + { "alertid": 5012, "tenantid": 1087, "locationid": 1097, + "type": "critical", // critical | warning | info + "title": "Stock Critical: RS Puram", + "details": "Dairy inventory below 5%.", + "createdat": "2026-06-06T08:24:00", + "acknowledged": false } +] +``` + +--- + +## B. STORE-WISE ANALYSIS + +### [R3] Product sales analytics β€” `GET /products/getproductanalytics` +The stock-statement mapper currently approximates `unitsSold = debit` and +`revenue = debit Γ— retailprice`. This returns true sales + the product meta the matrix shows. + +**Request** +| param | type | required | notes | +|---|---|---|---| +| tenantid | int | βœ“ | | +| locationid | int | | omit = across all outlets | +| subcategoryid | int | | | +| fromdate / todate | date | | sales window (default month-to-date) | +| keyword | string | | | +| pageno / pagesize | int | | | + +**Response `details`** (array) +```json +[ + { "productid": 88231, "productname": "Ponni Raw Rice 10kg", + "sku": "PONNI-RICE-10K", "categoryid": 2, "subcategoryname": "Rice", + "image": "https://…", + "unitssold": 12402, "revenue": 868140.00, "trend": "up", // up|flat|down + "closingstock": 1402, "maxcapacity": 2000, "binlocation": "BIN-C12", + "lastauditdate": "2026-06-05", "verified": true, + "outlets": [ { "locationid": 1097, "locationname": "RS Puram", "stock": 840 } ] } +] +``` +`outlets[]` gives the real per-hub split (replaces the hardcoded 60/40). `binlocation`, +`lastauditdate`, `image` replace the fabricated bin/barcode/audit fields β€” **drop them if the +catalog doesn't track them** rather than faking. + +--- + +### [R10] Intraday dispatch buckets β€” `GET /deliveries/getdispatchbuckets` +Replaces StoreDetail `intervalSlots` (Morning Rush / Midday / Evening Peak, computed from `%`). + +**Request**: `tenantid` (βœ“), `locationid` (βœ“), `date` (βœ“, default today). + +**Response `details`** (array, fixed buckets) +```json +[ + { "bucket": "06:00-10:00", "label": "Morning Rush", + "orders": 64, "revenue": 88400.00, "status": "PEAK" } // PEAK|HIGH|NORMAL|LOW +] +``` + +--- + +### [R11] Customer analytics β€” `GET /customers/getcustomeranalytics` +Replaces hardcoded CSAT 5.0 / retention 88.4% / AOV β‚Ή1,580 in StoreDetail. + +**Request**: `tenantid` (βœ“), `locationid` (optional), `customerid` (optional β€” single-customer rollup). + +**Response `details`** (object; per-customer when `customerid` set) +```json +{ + "retentionpct": 88.4, + "avgordervalue": 1580.00, + "csat": 4.9, + "totalcustomers": 1240, + "percustomer": { "customerid": 55012, "orderscount": 18, + "totalspent": 28450.00, "csat": 5.0, "lastorderdate": "2026-06-04" } +} +``` +> Customer order **history** itself is already available: `GET /orders/getorders?customerid=` (sheet row 56) β€” wire that, no new API needed. + +--- + +### [R9] Rider telemetry β€” `GET /partners/getridertelemetry` +Replaces hardcoded rider `rating 4.7`, `battery`, `lastPing`, and the fake GPS route / "9 MINS" / "1.2 km left". + +**Request**: `applocationid` (βœ“), `tenantid` (optional), `userid` (optional β€” single rider). + +**Response `details`** (array) +```json +[ + { "userid": 7781, "name": "Karthikeyan R", "status": "Delivering", // Delivering|Idle|Offline + "rating": 4.7, "completedtoday": 12, "battery": 84, + "lastping": "2026-06-06T14:21:00", "zone": "RS Puram", + "lat": 11.0041, "lng": 76.9612, + "activedelivery": { "deliveryid": 99213, "etamins": 9, "distancekm": 1.2, + "destlat": 11.0102, "destlng": 76.9550 } } +] +``` + +--- + +## C. REPORTS + +Reports are powered primarily by **[R1]** (revenue + deltas), **[R2]** (time-series chart & +ledger), and **[R3]** (product matrix). Additional reports-only needs: + +### [R4] Import / sync audit log β€” `GET /imports/getimportlogs` + validation +Replaces `initialImportLogs` and the hardcoded "14 duplicate SKUs" validator messages. + +**Request (list)**: `tenantid` (βœ“), `pageno`, `pagesize`. +**Response `details`** +```json +[ + { "importid": 921, "batchref": "#IMP_0921_A", "type": "Inventory Sync", + "source": "ERP Export", "rows": 421, "result": "SUCCESS", // SUCCESS|FAILED|PARTIAL + "message": "421 rows", "createdat": "2026-05-31T09:12:00" } +] +``` +**Upload (optional)**: `POST /imports/upload` (multipart csv) β†’ returns the same row plus a +`validation` block: +```json +{ "validation": { "passed": true, "duplicateskus": ["ST-SONA-25K"], + "badcolumns": [45, 82], "headerversion": "v2.8" } } +``` + +### [R13] Scheduled reports β€” `GET/POST /reports/getschedules` *(optional feature)* +Replaces the 3 hardcoded calendar events. Drop the feature if not on the roadmap. +```json +[ { "scheduleid": 11, "name": "Monthly Assortment Audit", "cron": "0 0 1 * *", + "nextrun": "2026-07-01T00:00:00", "format": "PDF", "recipients": ["ops@…"] } ] +``` + +--- + +## D. SETTINGS / CONFIG + +### [R6] Merchant settings + branding β€” `GET /tenants/getsettings`, `PUT /tenants/updatesettings` +Replaces `DEFAULTS` (localStorage) and the Brand Design Studio local state. Some fields already +live on the tenant (`minorder`, `paymenttype`) β€” fold those in. + +**GET response `details`** +```json +{ + "tenantid": 1087, + "contactemail": "ops@ragul.com", "contactphone": "+91…", + "minordervalue": 199, "deliverycharge": 29, "prepmins": 20, + "deliverywindowmins": 45, "cancelwindowsecs": 120, "autoassignrider": true, + "defaulttaxpercent": 5, "codenabled": true, "onlinepaymentenabled": true, + "defaultregion": "Coimbatore", "defaultnewuserrole": 4, + "ordernotifications": true, "lowstockalerts": true, "dailysummaryemail": false, + "syncinterval": 15, "sandboxmode": false, + "branding": { "themename": "Kaveri Org", "primarycolor": "#16a34a", + "secondarycolor": "#f59e0b", "baglabel": "Freshly Harvested", + "ecoverified": true, "stickerpattern": "radial" } +} +``` +**PUT body**: same object (partial allowed) β†’ returns updated object. + +--- + +## E. SUPPORTING OPERATIONAL ENDPOINTS (optional / phase-2) + +### [R7] Forecast / efficiency insight β€” `GET /insights/getforecast` +Operations "Forecast Efficiency 92% / β‚Ή1.9L savings". **Recommend removing** these tiles until a +forecasting model exists, rather than building a thin API. If kept: +```json +{ "forecastefficiencypct": 92, "estsavingsperweek": 190000.00, "horizondays": 7 } +``` + +### [R8] Stock transfer β€” `POST /products/stocktransfer` +Operations transfer-stock modal. +**Body**: `{ tenantid, productid, fromlocationid, tolocationid, quantity }` β†’ +**Response**: updated stock rows for both locations. + +### [R5] Catalog presets β€” `GET /products/getcatalogpresets` *(optional)* +Inventory "Nilgiris Dairy / Coimbatore Heritage" quick-add packs. Could instead reuse master +catalog listings (sheet row 90) filtered by subcategory β€” **prefer that, skip the new API**. + +--- + +## Mutation routes already in the sheet (confirm shape, then wire) +These are marked `REVIEW_REQUIRED` in the sheet β€” backend must publish request/response: +| Action | Route (sheet) | Used by | +|---|---|---| +| Create web order | POST orders+orderdetails | Orders "create order" | +| Update order status | PUT orders | Orders status buttons | +| Assign rider / dispatch | POST deliveries+deliverydetails | Orders assign-rider | +| Update pickup / delivered | PUT deliveries | Orders status progression | +| Add multi-product stock | POST (products) | Inventory/Operations add stock | +| Create/Update/Delete product | POST/PUT/DELETE | Catalogue management | +| Onboard tenant / store / location | POST/PUT | App add-store modal | diff --git a/docs/BACKEND_API_REQUIREMENTS.md b/docs/BACKEND_API_REQUIREMENTS.md new file mode 100644 index 0000000..2d01a74 --- /dev/null +++ b/docs/BACKEND_API_REQUIREMENTS.md @@ -0,0 +1,322 @@ +# Backend API Requirements β€” Merchant Web Console + +**Audience:** Backend team. +**Purpose:** These are the endpoints the merchant web app needs before it can go to staging with +zero mock data. Every UI spot listed below currently renders an explicit +`Awaiting backend API [Rxx]` placeholder (or a known-wrong stand-in like the +`delivered Γ— 355` revenue) until the matching endpoint ships. + +## Conventions (match the existing live API) +- **Base / proxy:** Fiesta REST at `https://fiesta.nearle.app/live/api/v1/web//`. + The frontend calls it through the dev proxy as `/fiesta/live/api/v1/web/...`. +- **Auth:** same as current read endpoints (no extra header required for GETs). +- **Envelope:** every response is + ```json + { "code": 200, "status": true, "message": "OK", "details": } + ``` + `details` is the documented payload (array or object). On failure return + `{ "code": 4xx, "status": false, "message": "" }`. +- **Types:** money = INR as a plain 2-dp number (e.g. `442800.00`), no currency symbol/string. + Dates = `YYYY-MM-DD`. Timestamps = ISO-8601 (`2026-06-06T14:21:00`). Ids = integers. +- **Tenant scope (current):** `tenantid=1087`, `applocationid=1`, primary `locationid=1097`. +- **Paging:** where listed, accept `pageno` (1-based) and `pagesize`. + +## Index +| Id | Endpoint | Method | Powers (UI) | Priority | +|---|---|---|---|---| +| [R1] | `/orders/getrevenuesummary` | GET | Revenue KPIs, OTIF, leaderboard, fulfilment health | **P0** | +| [R2] | `/orders/gettimeseries` | GET | Reports main chart, 7-day ledger | **P0** | +| [R3] | `/products/getproductanalytics` | GET | Product matrix sales + per-product detail | **P0** | +| [R4] | `/imports/getimportlogs` (+ `/imports/upload`) | GET/POST | Import audit stream + validator | P1 | +| [R5] | `/products/getcatalogpresets` | GET | Inventory catalog presets (optional) | P2 | +| [R6] | `/tenants/getsettings` (+ `/tenants/updatesettings`) | GET/PUT | Settings + Brand studio | P1 | +| [R7] | `/insights/getforecast` | GET | Operations forecast tiles (optional) | P2 | +| [R8] | `/products/stocktransfer` | POST | Operations stock-transfer modal | P1 | +| [R9] | `/partners/getridertelemetry` | GET | Fleet rating, GPS, ETA | P1 | +| [R10] | `/deliveries/getdispatchbuckets` | GET | StoreDetail intraday dispatch | P1 | +| [R11] | `/customers/getcustomeranalytics` | GET | Customer CSAT/AOV/retention | P1 | +| [R12] | `/alerts/getalerts` | GET | Operational alerts feed | P1 | +| [R13] | `/reports/getschedules` (+ POST) | GET/POST | Scheduled reports (optional) | P2 | + +Plus **mutation routes** already named in the endpoint sheet but not yet shape-documented β€” see +the last section. + +--- + +## [R1] Revenue summary Β· `GET /orders/getrevenuesummary` +Real money totals. Today the app fakes revenue as `delivered Γ— 355` β€” replace that. + +**Request (query params)** +| param | type | required | notes | +|---|---|---|---| +| `tenantid` | int | βœ“ | | +| `locationid` | int | | omit β†’ all outlets (overall); set β†’ store-wise | +| `fromdate` | date | βœ“ | | +| `todate` | date | βœ“ | | + +**Response `details`** (single object) +```json +{ + "tenantid": 1087, + "locationid": null, + "grossrevenue": 1248302.00, + "netrevenue": 1180500.00, + "profit": 354216.00, + "marginpct": 28.4, + "ordercount": 4921, + "deliveredcount": 4102, + "cancelledcount": 142, + "otifpct": 98.2, + "avgordervalue": 1580.00, + "prev_grossrevenue": 1090000.00, + "prev_ordercount": 4370 +} +``` +`prev_*` = same metric for the immediately preceding equal-length window (lets the UI show +`+14.2%` deltas without a second call). `otifpct` powers the OTIF / fulfilment-health tiles. +Frontend hook to add: `useFiestaRevenueSummary`. + +--- + +## [R2] Orders / revenue time-series Β· `GET /orders/gettimeseries` +Powers the Reports main chart (Orders / Revenue / Cancelled / SKUs) and StoreDetail 7-day ledger. + +**Request** +| param | type | required | notes | +|---|---|---|---| +| `tenantid` | int | βœ“ | | +| `locationid` | int | | omit β†’ overall | +| `granularity` | enum | βœ“ | `day` \| `month` \| `year` | +| `fromdate` | date | βœ“ | | +| `todate` | date | βœ“ | | + +**Response `details`** (array, one bucket per period) +```json +[ + { "label": "2026-06-01", "orders": 312, "revenue": 442800.00, + "delivered": 298, "cancelled": 9, "activeskus": 72 } +] +``` +`label` = `YYYY-MM-DD` (day), `YYYY-MM` (month), or `YYYY` (year). Removes all hardcoded chart +arrays and the region-scaling multipliers (filter by `locationid` instead). +Frontend hook: `useFiestaTimeSeries`. + +--- + +## [R3] Product sales analytics Β· `GET /products/getproductanalytics` +True units-sold + revenue per product, plus the per-product/per-outlet detail the matrix expands. + +**Request** +| param | type | required | notes | +|---|---|---|---| +| `tenantid` | int | βœ“ | | +| `locationid` | int | | omit β†’ across all outlets | +| `subcategoryid` | int | | | +| `fromdate` / `todate` | date | | sales window (default month-to-date) | +| `keyword` | string | | | +| `pageno` / `pagesize` | int | | | + +**Response `details`** (array) +```json +[ + { "productid": 88231, "productname": "Ponni Raw Rice 10kg", + "sku": "PONNI-RICE-10K", "categoryid": 2, "subcategoryname": "Rice", + "image": "https://…", + "unitssold": 12402, "revenue": 868140.00, "trend": "up", + "closingstock": 1402, "maxcapacity": 2000, + "binlocation": "BIN-C12", "lastauditdate": "2026-06-05", "verified": true, + "outlets": [ { "locationid": 1097, "locationname": "RS Puram", "stock": 840 } ] } +] +``` +`trend` ∈ `up|flat|down`. `outlets[]` = real per-hub split (replaces hardcoded 60/40). +If the catalog doesn't track `binlocation`/`lastauditdate`, return `null` β€” the UI will hide them +rather than fake them. Frontend hook: `useFiestaProductAnalytics`. + +--- + +## [R4] Import / sync audit log Β· `GET /imports/getimportlogs` + `POST /imports/upload` +Replaces the mock "Live Sync Audit Stream" and the hardcoded "14 duplicate SKUs" validator. + +**GET request:** `tenantid` (βœ“), `pageno`, `pagesize`. +**GET `details`** +```json +[ + { "importid": 921, "batchref": "#IMP_0921_A", "type": "Inventory Sync", + "source": "ERP Export", "rows": 421, "result": "SUCCESS", + "message": "421 rows imported", "createdat": "2026-05-31T09:12:00" } +] +``` +`result` ∈ `SUCCESS|FAILED|PARTIAL`. + +**POST `/imports/upload`** (multipart, field `file` = CSV; plus `tenantid`) β†’ returns the new log row +plus a validation block: +```json +{ "importid": 922, "result": "PARTIAL", + "validation": { "passed": false, "duplicateskus": ["ST-SONA-25K"], + "badcolumns": [45, 82], "headerversion": "v2.8" } } +``` +Frontend hooks: `useFiestaImportLogs`, `useFiestaImportUpload` (mutation). + +--- + +## [R5] Catalog presets *(optional)* Β· `GET /products/getcatalogpresets` +Inventory "Nilgiris Dairy / Coimbatore Heritage" quick-add packs. +**Request:** `tenantid` (βœ“). **`details`:** +```json +[ { "presetid": 3, "name": "Nilgiris Dairy Fresh Pack", + "items": [ { "name": "Ooty Butter 500g", "sku": "DY-OOT-BTR", + "subcategoryname": "Dairy", "price": 340, "image": "https://…" } ] } ] +``` +> Alternative: skip this and reuse master catalog (`/products/getproducts`) filtered by subcategory. + +--- + +## [R6] Merchant settings + branding Β· `GET /tenants/getsettings` + `PUT /tenants/updatesettings` +Replaces the localStorage `DEFAULTS` and the Brand Design Studio local state. + +**GET request:** `tenantid` (βœ“). **GET `details`:** +```json +{ + "tenantid": 1087, + "contactemail": "ops@ragul.com", "contactphone": "+91…", + "minordervalue": 199, "deliverycharge": 29, "prepmins": 20, + "deliverywindowmins": 45, "cancelwindowsecs": 120, "autoassignrider": true, + "defaulttaxpercent": 5, "codenabled": true, "onlinepaymentenabled": true, + "defaultregion": "Coimbatore", "defaultnewuserrole": 4, + "ordernotifications": true, "lowstockalerts": true, "dailysummaryemail": false, + "syncinterval": 15, "sandboxmode": false, + "branding": { "themename": "Kaveri Org", "primarycolor": "#16a34a", + "secondarycolor": "#f59e0b", "baglabel": "Freshly Harvested", + "ecoverified": true, "stickerpattern": "radial" } +} +``` +**PUT body:** same object (partial allowed) β†’ returns the updated object. +Frontend hooks: `useFiestaSettings`, `useFiestaUpdateSettings` (mutation). + +--- + +## [R7] Forecast insight *(optional)* Β· `GET /insights/getforecast` +Operations "Forecast Efficiency 92% / β‚Ή1.9L savings". Recommend dropping the tiles until a model +exists; if kept: **request** `tenantid` (βœ“), `locationid` (opt). **`details`:** +```json +{ "forecastefficiencypct": 92, "estsavingsperweek": 190000.00, "horizondays": 7 } +``` + +--- + +## [R8] Stock transfer Β· `POST /products/stocktransfer` +Operations transfer-stock modal. +**Body:** +```json +{ "tenantid": 1087, "productid": 88231, + "fromlocationid": 1097, "tolocationid": 1101, "quantity": 100 } +``` +**`details`:** updated stock rows for both locations +```json +[ { "locationid": 1097, "productid": 88231, "closingstock": 740 }, + { "locationid": 1101, "productid": 88231, "closingstock": 360 } ] +``` + +--- + +## [R9] Rider telemetry Β· `GET /partners/getridertelemetry` +Replaces hardcoded rider `rating`, `battery`, `lastPing` and the fake GPS route / "9 MINS" / "1.2 km". + +**Request:** `applocationid` (βœ“), `tenantid` (opt), `userid` (opt β†’ single rider). +**`details`** (array) +```json +[ + { "userid": 7781, "name": "Karthikeyan R", "status": "Delivering", + "rating": 4.7, "completedtoday": 12, "battery": 84, + "lastping": "2026-06-06T14:21:00", "zone": "RS Puram", + "lat": 11.0041, "lng": 76.9612, + "activedelivery": { "deliveryid": 99213, "etamins": 9, "distancekm": 1.2, + "destlat": 11.0102, "destlng": 76.9550 } } +] +``` +`status` ∈ `Delivering|Idle|Offline`. `activedelivery` = `null` when the rider is idle. +Frontend hook: `useFiestaRiderTelemetry`. + +--- + +## [R10] Intraday dispatch buckets Β· `GET /deliveries/getdispatchbuckets` +Replaces StoreDetail `intervalSlots` (Morning Rush / Midday / Evening Peak computed from %). + +**Request:** `tenantid` (βœ“), `locationid` (βœ“), `date` (βœ“, default today). +**`details`** (array, fixed buckets) +```json +[ { "bucket": "06:00-10:00", "label": "Morning Rush", + "orders": 64, "revenue": 88400.00, "status": "PEAK" } ] +``` +`status` ∈ `PEAK|HIGH|NORMAL|LOW`. Frontend hook: `useFiestaDispatchBuckets`. + +--- + +## [R11] Customer analytics Β· `GET /customers/getcustomeranalytics` +Replaces hardcoded CSAT 5.0 / retention 88.4% / AOV β‚Ή1,580. + +**Request:** `tenantid` (βœ“), `locationid` (opt), `customerid` (opt β†’ single-customer rollup). +**`details`** (object) +```json +{ + "retentionpct": 88.4, "avgordervalue": 1580.00, "csat": 4.9, + "totalcustomers": 1240, + "percustomer": { "customerid": 55012, "orderscount": 18, + "totalspent": 28450.00, "csat": 5.0, "lastorderdate": "2026-06-04" } +} +``` +`percustomer` present only when `customerid` is supplied. +> Customer order **history** itself already exists: `GET /orders/getorders?customerid=` β€” wire that, no new API. +Frontend hook: `useFiestaCustomerAnalytics`. + +--- + +## [R12] Operational alerts Β· `GET /alerts/getalerts` +Replaces the mock `operationalAlerts` (stock-critical, latency, rebalance…). + +**Request:** `tenantid` (βœ“), `locationid` (opt), `status` (`open|all`), `pageno`, `pagesize`. +**`details`** (array) +```json +[ { "alertid": 5012, "tenantid": 1087, "locationid": 1097, + "type": "critical", "title": "Stock Critical: RS Puram", + "details": "Dairy inventory below 5%.", + "createdat": "2026-06-06T08:24:00", "acknowledged": false } ] +``` +`type` ∈ `critical|warning|info`. Frontend hook: `useFiestaAlerts`. + +--- + +## [R13] Scheduled reports *(optional)* Β· `GET /reports/getschedules` + `POST /reports/createschedule` +Replaces 3 hardcoded calendar events. Drop if not on the roadmap. +**GET `details`:** +```json +[ { "scheduleid": 11, "name": "Monthly Assortment Audit", "cron": "0 0 1 * *", + "nextrun": "2026-07-01T00:00:00", "format": "PDF", "recipients": ["ops@ragul.com"] } ] +``` +**POST body:** `{ tenantid, name, cron, format, recipients[] }` β†’ returns the created schedule. + +--- + +## Mutation routes already named in the endpoint sheet (publish request/response, then we wire) +These are marked `REVIEW_REQUIRED` in `Fiesta_All_Endpoints_With_Tables_And_Params.xlsx`. We need +the exact request body + success response for each: + +| Action | Suggested endpoint | Body (fields we'll send) | +|---|---|---| +| Create web order | `POST /orders/create` | tenantid, locationid, customerid, items[{productid,qty,price}], paymenttype | +| Update order status | `PUT /orders/updatestatus` | orderheaderid, status, financialflag | +| Assign rider / dispatch | `POST /deliveries/assign` | orderheaderid, tenantid, locationid, partnerid, userid | +| Update pickup / delivered | `PUT /deliveries/updatestatus` | deliveryid, status | +| Add multi-product stock | `POST /products/addstock` | tenantid, locationid, items[{productid,qty,cost}] | +| Create / update / delete product | `POST/PUT/DELETE /products/...` | product fields | +| Onboard tenant / store / location | `POST /tenants/onboard`, `POST /tenants/createlocation` | tenant + location fields | + +--- + +## Frontend status (for reference) +- All read endpoints that **already exist** are wired (orders/deliveries/stock/customers/users/ + locations/order-line-items/etc.). +- Each `[Rxx]` above corresponds to a visible `AwaitingApi` placeholder in the UI, so QA can see + exactly which screens are still blocked. +- The moment an endpoint here ships with the documented shape, wiring it is one hook + swapping the + placeholder β€” no redesign needed. diff --git a/docs/_endpoints_raw.txt b/docs/_endpoints_raw.txt new file mode 100644 index 0000000..0eddabb --- /dev/null +++ b/docs/_endpoints_raw.txt @@ -0,0 +1,105 @@ +API Name | Method | Exact Table | Query Parameters +Utils | GET | app_types | tag +Resolve subcategories (Web) | GET | app_subcategory | moduleid, categoryid +Fetch system active geofence details (Web) | GET | app_location | applocationid +Fetch global system categories configurations (Web) | GET | app_category | None +Get mobile geofence configuration details (Mobile) | GET | app_locationconfig | applocationid +Get mobile active geofence details (Mobile) | GET | app_location | applocationid +Fetch mobile app types by tag (Mobile) | GET | app_types | tag +Fetch global payment & geofence configs (Mobile) | GET | app_config | configid +Get mobile category subcategories list (Mobile) | GET | app_subcategory | moduleid, categoryid +Fetch mobile app categories configurations (Mobile) | GET | app_category | None +Users | GET | users | roleid, tenantid, pageno, pagesize, keyword +Get a specific user profile by ID (Web) | GET | users | userid +Get a specific user profile by ID (Mobile) | GET | users | userid +Operator/User orders board (Web) | GET | orders | appuserid, status, pageno, pagesize +Tenant Web Panel Login | POST | REVIEW_REQUIRED | None +General Application Login | POST | REVIEW_REQUIRED | None +Register New Web Staff Account | POST | REVIEW_REQUIRED | None +Update Web Staff User Details | PUT | REVIEW_REQUIRED | None +Rider/Merchant Mobile App Login | POST | REVIEW_REQUIRED | None +Create Mobile Staff User | POST | REVIEW_REQUIRED | None +Update Mobile Staff Details | PUT | REVIEW_REQUIRED | None +Partners | GET | orders | partnerid, status, pageno, pagesize +Get active riders (Web) | GET | partneruser | partnerid, applocationid, userid, tenantid +Get partner profiles (Web) | GET | partneruser | partnerid, applocationid, userid +Get rider shifts (Web) | GET | partneruser | applocationid +Get location configurations (Web) | GET | REVIEW_REQUIRED | userid, configid +Get rider log sheet (Web) | GET | riderlogs | partnerid, applocationid, fromdate, todate +Get partner profiles (Mobile) | GET | partneruser | partnerid, applocationid, userid +Get rider log sheet (Mobile) | GET | riderlogs | partnerid, applocationid, fromdate, todate +Get rider operational info (Mobile) | GET | partneruser | userid +Get active riders list (Mobile) | GET | partneruser | partnerid, applocationid, userid, tenantid +Tenants | GET | orders | tenantid, locationid, status, pageno, pagesize +Get specific tenant store orders (Mobile) | GET | orders | tenantid, locationid, pageno, pagesize +Search registered tenants (Web) | GET | REVIEW_REQUIRED | status, keyword +Search tenants by keyword (Web) | GET | REVIEW_REQUIRED | keyword +Get all active tenants catalog (Web) | GET | tenants | applocationid, status, pageno, pagesize +Get outlet locations assigned to a tenant (Web) | GET | tenantlocations | tenantid +Retrieve delivery time slots config (Mobile) | GET | tenantslot | None +Search tenants by keyword (Mobile) | GET | REVIEW_REQUIRED | keyword +Retrieve tenants associated with a customer (Mobile) | GET | tenantcustomers | customerid, tenant +Get outlet locations linked to a tenant (Mobile) | GET | tenantlocations | tenantid +Get logistics pricing slabs for a tenant (Mobile) | GET | tenantpricing | tenantid, applocationid +Get staff members under a tenant store (Mobile) | GET | tenantstaffs | tenantid +Get tenant detailed profile info (Mobile) | GET | tenants | tenantid, locationid +Link Customer Profile to Tenant Store | POST | REVIEW_REQUIRED | None +Create New Geofenced Store Location | POST | REVIEW_REQUIRED | None +Update Store Location Configurations | PUT | REVIEW_REQUIRED | None +Onboard New Tenant & Admin Profile | POST | REVIEW_REQUIRED | None +Customers | GET | customers | customerid, contactno +Get customer saved address locations (Mobile) | GET | customerlocations | customerid +Get customer logged support requests (Mobile) | GET | customerrequest | customerid, pageno, pagesize +Search customer names under a tenant (Mobile) | GET | REVIEW_REQUIRED | keyword, tenantid +Retrieve customers linked to a tenant location (Mobile) | GET | tenantcustomers | tenantid, locationid, pageno, pagesize +Retrieve merchant customers list (Web) | GET | tenantcustomers | tenantid, locationid, pageno, pagesize, keyword +Individual consumer invoice histories (Web) | GET | orders | customerid, status, pageno, pagesize +Passwordless OTP Login (via Phone) | POST | REVIEW_REQUIRED | None +Register Customer Account | POST | REVIEW_REQUIRED | None +Save New Geofenced Location Address | POST | REVIEW_REQUIRED | None +Log Customer Support Ticket Request | POST | REVIEW_REQUIRED | None +Update Customer Profile Details | PUT | REVIEW_REQUIRED | None +Deliveries | GET | deliveries | tenantid, partnerid, userid, applocationid, locationid, fromdate, todate +Get daily delivery insights (Web) | GET | deliveries | tenantid +Get location deliveries summary (Web) | GET | deliveries | tenantid +Get deliveries financial report summary (Web) | GET | deliveries | tenantid, partnerid, userid, applocationid, fromdate, todate +Get fleet rider summary metrics (Web) | GET | partneruser | applocationid, partnerid, tenantid, fromdate, todate +Get master deliveries board (Web) | GET | deliveries | tenantid, fromdate, todate +Get mobile dispatch summaries (Mobile) | GET | deliveries | userid, fromdate, todate +Get mobile deliveries board (Mobile) | GET | deliveries | userid, status +Fetch rider active shift deliveries queue (Mobile) | GET | deliveryqueues | userid, fromdate, todate +Initialize Logistics Delivery Dispatch (Assign Rider) | POST | deliveries + deliverydetails | None +Update Rider Pickup Status | PUT | deliveries | None +Rider Update Dispatch Status (Delivered) | PUT | deliveries | None +Orders | GET | orders | tenantid, locationid, status, pageno, pagesize +System Admin orders board (Web) | GET | orders | applocationid, status, pageno, pagesize +Get order dashboard stats summary (Web) | GET | orders | tenantid, fromdate, todate +Get location orders summary (Web) | GET | deliveries | tenantid +Get annual orders insights analytics (Web) | GET | orders | tenantid +Get order detailed lines (Web) | GET | orderdetails | orderheaderid +Get customer order history (Mobile) | GET | orders | customerid, pageno, pagesize +Get mobile order detailed lines (Mobile) | GET | orderdetails | orderheaderid +Create New Web Order | POST | orders + orderdetails | None +Update Order Status & Financial Flag | PUT | orders | None +Create Mobile Order | POST | orders + orderdetails | None +Mobile Update Order Status | PUT | orders | None +Products | GET | productsubcategories | categoryid, tenantid +Get products stock counts (Web) | GET | products | tenantid, categoryid, subcategoryid, approve +Get all global categories (Web) | GET | productcategories | None +Get specific product variants (Web) | GET | productvariants | tenantid, subcategoryid +Get master catalog listings (Web) | GET | products | tenantid, locationid, subcategoryid, keyword, pageno, pagesize +Get live stocks catalog (Web) | GET | productstocks | tenantid, locationid +Get dynamic stock statement ledger (Web) | GET | product_stock_statement | tenantid, locationid, subcategoryid, pageno, pagesize, keyword +Get outlet geofenced inventory (Web) | GET | productlocations | tenantid, locationid, subcategoryid, pageno, pagesize +Master products search board (Web) | GET | products | tenantid, locationid, keyword, pageno, pagesize +Get product details by variant ID (Mobile) | GET | productvariants | tenantid, variantid +Get product subcategories (Mobile) | GET | productsubcategories | categoryid, tenantid +Search product catalog (Mobile) | GET | products | keyword, pageno, pagesize +Get mobile geofenced outlet products (Mobile) | GET | productlocations | tenantid, locationid, pageno, pagesize +Add Multi-Product Stock Entry | POST | REVIEW_REQUIRED | None +Create Master Product Catalog Item | POST | REVIEW_REQUIRED | None +Update Master Product Details | PUT | REVIEW_REQUIRED | None +Purge Master Product Catalog Entry | DELETE | REVIEW_REQUIRED | productid +Invoice | GET | invoice_insight | tenantid +Payments | GET | paymentrequests | partnerid, status +TOTAL ROWS: 104 diff --git a/spec_bundle.js b/spec_bundle.js new file mode 100644 index 0000000..39061b0 --- /dev/null +++ b/spec_bundle.js @@ -0,0 +1,1009 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))l(n);new MutationObserver(n=>{for(const i of n)if(i.type==="childList")for(const u of i.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&l(u)}).observe(document,{childList:!0,subtree:!0});function a(n){const i={};return n.integrity&&(i.integrity=n.integrity),n.referrerPolicy&&(i.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?i.credentials="include":n.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function l(n){if(n.ep)return;n.ep=!0;const i=a(n);fetch(n.href,i)}})();var or={exports:{}},Si={};/** + * @license React + * react-jsx-runtime.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Mm=Symbol.for("react.transitional.element"),Am=Symbol.for("react.fragment");function rr(e,t,a){var l=null;if(a!==void 0&&(l=""+a),t.key!==void 0&&(l=""+t.key),"key"in t){a={};for(var n in t)n!=="key"&&(a[n]=t[n])}else a=t;return t=a.ref,{$$typeof:Mm,type:e,key:l,ref:t!==void 0?t:null,props:a}}Si.Fragment=Am;Si.jsx=rr;Si.jsxs=rr;or.exports=Si;var y=or.exports,fr={exports:{}},O={};/** + * @license React + * react.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Tc=Symbol.for("react.transitional.element"),Gm=Symbol.for("react.portal"),Nm=Symbol.for("react.fragment"),Om=Symbol.for("react.strict_mode"),qm=Symbol.for("react.profiler"),Um=Symbol.for("react.consumer"),Dm=Symbol.for("react.context"),jm=Symbol.for("react.forward_ref"),Cm=Symbol.for("react.suspense"),Rm=Symbol.for("react.memo"),dr=Symbol.for("react.lazy"),Hm=Symbol.for("react.activity"),xs=Symbol.iterator;function Bm(e){return e===null||typeof e!="object"?null:(e=xs&&e[xs]||e["@@iterator"],typeof e=="function"?e:null)}var mr={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},pr=Object.assign,yr={};function al(e,t,a){this.props=e,this.context=t,this.refs=yr,this.updater=a||mr}al.prototype.isReactComponent={};al.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};al.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function gr(){}gr.prototype=al.prototype;function xc(e,t,a){this.props=e,this.context=t,this.refs=yr,this.updater=a||mr}var Ec=xc.prototype=new gr;Ec.constructor=xc;pr(Ec,al.prototype);Ec.isPureReactComponent=!0;var Es=Array.isArray;function zu(){}var W={H:null,A:null,T:null,S:null},vr=Object.prototype.hasOwnProperty;function _c(e,t,a){var l=a.ref;return{$$typeof:Tc,type:e,key:t,ref:l!==void 0?l:null,props:a}}function Ym(e,t){return _c(e.type,t,e.props)}function zc(e){return typeof e=="object"&&e!==null&&e.$$typeof===Tc}function wm(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(a){return t[a]})}var _s=/\/+/g;function Qi(e,t){return typeof e=="object"&&e!==null&&e.key!=null?wm(""+e.key):t.toString(36)}function Qm(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(zu,zu):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function Ea(e,t,a,l,n){var i=typeof e;(i==="undefined"||i==="boolean")&&(e=null);var u=!1;if(e===null)u=!0;else switch(i){case"bigint":case"string":case"number":u=!0;break;case"object":switch(e.$$typeof){case Tc:case Gm:u=!0;break;case dr:return u=e._init,Ea(u(e._payload),t,a,l,n)}}if(u)return n=n(e),u=l===""?"."+Qi(e,0):l,Es(n)?(a="",u!=null&&(a=u.replace(_s,"$&/")+"/"),Ea(n,t,a,"",function(f){return f})):n!=null&&(zc(n)&&(n=Ym(n,a+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(_s,"$&/")+"/")+u)),t.push(n)),1;u=0;var c=l===""?".":l+":";if(Es(e))for(var s=0;s>>1,de=E[ae];if(0>>1;aen(wi,U))ean(dn,wi)?(E[ae]=dn,E[ea]=U,ae=ea):(E[ae]=wi,E[fn]=U,ae=fn);else if(ean(dn,U))E[ae]=dn,E[ea]=U,ae=ea;else break e}}return j}function n(E,j){var U=E.sortIndex-j.sortIndex;return U!==0?U:E.id-j.id}if(e.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var u=Date,c=u.now();e.unstable_now=function(){return u.now()-c}}var s=[],f=[],g=1,v=null,d=3,p=!1,S=!1,x=!1,D=!1,r=typeof setTimeout=="function"?setTimeout:null,o=typeof clearTimeout=="function"?clearTimeout:null,m=typeof setImmediate<"u"?setImmediate:null;function h(E){for(var j=a(f);j!==null;){if(j.callback===null)l(f);else if(j.startTime<=E)l(f),j.sortIndex=j.expirationTime,t(s,j);else break;j=a(f)}}function _(E){if(x=!1,h(E),!S)if(a(s)!==null)S=!0,z||(z=!0,_e());else{var j=a(f);j!==null&&Yi(_,j.startTime-E)}}var z=!1,T=-1,M=5,A=-1;function N(){return D?!0:!(e.unstable_now()-AE&&N());){var ae=v.callback;if(typeof ae=="function"){v.callback=null,d=v.priorityLevel;var de=ae(v.expirationTime<=E);if(E=e.unstable_now(),typeof de=="function"){v.callback=de,h(E),j=!0;break t}v===a(s)&&l(s),h(E)}else l(s);v=a(s)}if(v!==null)j=!0;else{var rn=a(f);rn!==null&&Yi(_,rn.startTime-E),j=!1}}break e}finally{v=null,d=U,p=!1}j=void 0}}finally{j?_e():z=!1}}}var _e;if(typeof m=="function")_e=function(){m(ie)};else if(typeof MessageChannel<"u"){var Mt=new MessageChannel,rl=Mt.port2;Mt.port1.onmessage=ie,_e=function(){rl.postMessage(null)}}else _e=function(){r(ie,0)};function Yi(E,j){T=r(function(){E(e.unstable_now())},j)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(E){E.callback=null},e.unstable_forceFrameRate=function(E){0>E||125ae?(E.sortIndex=U,t(f,E),a(s)===null&&E===a(f)&&(x?(o(T),T=-1):x=!0,Yi(_,U-ae))):(E.sortIndex=de,t(s,E),S||p||(S=!0,z||(z=!0,_e()))),E},e.unstable_shouldYield=N,e.unstable_wrapCallback=function(E){var j=d;return function(){var U=d;d=j;try{return E.apply(this,arguments)}finally{d=U}}}})(Sr);br.exports=Sr;var Zm=br.exports,Tr={exports:{}},Ee={};/** + * @license React + * react-dom.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Vm=P;function xr(e){var t="https://react.dev/errors/"+e;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Er)}catch(e){console.error(e)}}Er(),Tr.exports=Ee;var $m=Tr.exports;/** + * @license React + * react-dom-client.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var fe=Zm,_r=P,km=$m;function b(e){var t="https://react.dev/errors/"+e;if(1Aa||(e.current=qu[Aa],qu[Aa]=null,Aa--)}function K(e,t){Aa++,qu[Aa]=e.current,e.current=t}var nt=it(null),Hl=it(null),Yt=it(null),Zn=it(null);function Vn(e,t){switch(K(Yt,t),K(Hl,e),K(nt,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?jo(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=jo(t),e=Fd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}ye(nt),K(nt,e)}function Va(){ye(nt),ye(Hl),ye(Yt)}function Uu(e){e.memoizedState!==null&&K(Zn,e);var t=nt.current,a=Fd(t,e.type);t!==a&&(K(Hl,e),K(nt,a))}function Kn(e){Hl.current===e&&(ye(nt),ye(Hl)),Zn.current===e&&(ye(Zn),$l._currentValue=ua)}var Li,Gs;function aa(e){if(Li===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);Li=t&&t[1]||"",Gs=-1)":-1n||s[l]!==f[n]){var g=` +`+s[l].replace(" at new "," at ");return e.displayName&&g.includes("")&&(g=g.replace("",e.displayName)),g}while(1<=l&&0<=n);break}}}finally{Xi=!1,Error.prepareStackTrace=a}return(a=e?e.displayName||e.name:"")?aa(a):""}function e0(e,t){switch(e.tag){case 26:case 27:case 5:return aa(e.type);case 16:return aa("Lazy");case 13:return e.child!==t&&t!==null?aa("Suspense Fallback"):aa("Suspense");case 19:return aa("SuspenseList");case 0:case 15:return Zi(e.type,!1);case 11:return Zi(e.type.render,!1);case 1:return Zi(e.type,!0);case 31:return aa("Activity");default:return""}}function Ns(e){try{var t="",a=null;do t+=e0(e,a),a=e,e=e.return;while(e);return t}catch(l){return` +Error generating stack: `+l.message+` +`+l.stack}}var Du=Object.prototype.hasOwnProperty,Gc=fe.unstable_scheduleCallback,Vi=fe.unstable_cancelCallback,t0=fe.unstable_shouldYield,a0=fe.unstable_requestPaint,Re=fe.unstable_now,l0=fe.unstable_getCurrentPriorityLevel,qr=fe.unstable_ImmediatePriority,Ur=fe.unstable_UserBlockingPriority,Jn=fe.unstable_NormalPriority,n0=fe.unstable_LowPriority,Dr=fe.unstable_IdlePriority,i0=fe.log,u0=fe.unstable_setDisableYieldValue,Il=null,He=null;function jt(e){if(typeof i0=="function"&&u0(e),He&&typeof He.setStrictMode=="function")try{He.setStrictMode(Il,e)}catch{}}var Be=Math.clz32?Math.clz32:o0,c0=Math.log,s0=Math.LN2;function o0(e){return e>>>=0,e===0?32:31-(c0(e)/s0|0)|0}var yn=256,gn=262144,vn=4194304;function la(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Ei(e,t,a){var l=e.pendingLanes;if(l===0)return 0;var n=0,i=e.suspendedLanes,u=e.pingedLanes;e=e.warmLanes;var c=l&134217727;return c!==0?(l=c&~i,l!==0?n=la(l):(u&=c,u!==0?n=la(u):a||(a=c&~e,a!==0&&(n=la(a))))):(c=l&~i,c!==0?n=la(c):u!==0?n=la(u):a||(a=l&~e,a!==0&&(n=la(a)))),n===0?0:t!==0&&t!==n&&!(t&i)&&(i=n&-n,a=t&-t,i>=a||i===32&&(a&4194048)!==0)?t:n}function Pl(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function r0(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function jr(){var e=vn;return vn<<=1,!(vn&62914560)&&(vn=4194304),e}function Ki(e){for(var t=[],a=0;31>a;a++)t.push(e);return t}function en(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function f0(e,t,a,l,n,i){var u=e.pendingLanes;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=a,e.entangledLanes&=a,e.errorRecoveryDisabledLanes&=a,e.shellSuspendCounter=0;var c=e.entanglements,s=e.expirationTimes,f=e.hiddenUpdates;for(a=u&~a;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var v0=/[\n"\\]/g;function Ke(e){return e.replace(v0,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Ru(e,t,a,l,n,i,u,c){e.name="",u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"?e.type=u:e.removeAttribute("type"),t!=null?u==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Xe(t)):e.value!==""+Xe(t)&&(e.value=""+Xe(t)):u!=="submit"&&u!=="reset"||e.removeAttribute("value"),t!=null?Hu(e,u,Xe(t)):a!=null?Hu(e,u,Xe(a)):l!=null&&e.removeAttribute("value"),n==null&&i!=null&&(e.defaultChecked=!!i),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.name=""+Xe(c):e.removeAttribute("name")}function Xr(e,t,a,l,n,i,u,c){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||a!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){Cu(e);return}a=a!=null?""+Xe(a):"",t=t!=null?""+Xe(t):a,c||t===e.value||(e.value=t),e.defaultValue=t}l=l??n,l=typeof l!="function"&&typeof l!="symbol"&&!!l,e.checked=c?e.checked:!!l,e.defaultChecked=!!l,u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.name=u),Cu(e)}function Hu(e,t,a){t==="number"&&$n(e.ownerDocument)===e||e.defaultValue===""+a||(e.defaultValue=""+a)}function Ya(e,t,a,l){if(e=e.options,t){t={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Yu=!1;if(St)try{var dl={};Object.defineProperty(dl,"passive",{get:function(){Yu=!0}}),window.addEventListener("test",dl,dl),window.removeEventListener("test",dl,dl)}catch{Yu=!1}var Ct=null,jc=null,qn=null;function $r(){if(qn)return qn;var e,t=jc,a=t.length,l,n="value"in Ct?Ct.value:Ct.textContent,i=n.length;for(e=0;e=_l),ws=" ",Qs=!1;function Wr(e,t){switch(e){case"keyup":return V0.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Fr(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Oa=!1;function J0(e,t){switch(e){case"compositionend":return Fr(t);case"keypress":return t.which!==32?null:(Qs=!0,ws);case"textInput":return e=t.data,e===ws&&Qs?null:e;default:return null}}function $0(e,t){if(Oa)return e==="compositionend"||!Rc&&Wr(e,t)?(e=$r(),qn=jc=Ct=null,Oa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:a,offset:t-e};e=l}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=Ks(a)}}function tf(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?tf(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function af(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=$n(e.document);t instanceof e.HTMLIFrameElement;){try{var a=typeof t.contentWindow.location.href=="string"}catch{a=!1}if(a)e=t.contentWindow;else break;t=$n(e.document)}return t}function Hc(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var a1=St&&"documentMode"in document&&11>=document.documentMode,qa=null,wu=null,Ml=null,Qu=!1;function $s(e,t,a){var l=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;Qu||qa==null||qa!==$n(l)||(l=qa,"selectionStart"in l&&Hc(l)?l={start:l.selectionStart,end:l.selectionEnd}:(l=(l.ownerDocument&&l.ownerDocument.defaultView||window).getSelection(),l={anchorNode:l.anchorNode,anchorOffset:l.anchorOffset,focusNode:l.focusNode,focusOffset:l.focusOffset}),Ml&&wl(Ml,l)||(Ml=l,l=di(wu,"onSelect"),0>=u,n-=u,tt=1<<32-Be(t)+n|a<M?(A=T,T=null):A=T.sibling;var N=d(r,T,m[M],h);if(N===null){T===null&&(T=A);break}e&&T&&N.alternate===null&&t(r,T),o=i(N,o,M),z===null?_=N:z.sibling=N,z=N,T=A}if(M===m.length)return a(r,T),B&&dt(r,M),_;if(T===null){for(;MM?(A=T,T=null):A=T.sibling;var ie=d(r,T,N.value,h);if(ie===null){T===null&&(T=A);break}e&&T&&ie.alternate===null&&t(r,T),o=i(ie,o,M),z===null?_=ie:z.sibling=ie,z=ie,T=A}if(N.done)return a(r,T),B&&dt(r,M),_;if(T===null){for(;!N.done;M++,N=m.next())N=v(r,N.value,h),N!==null&&(o=i(N,o,M),z===null?_=N:z.sibling=N,z=N);return B&&dt(r,M),_}for(T=l(T);!N.done;M++,N=m.next())N=p(T,r,M,N.value,h),N!==null&&(e&&N.alternate!==null&&T.delete(N.key===null?M:N.key),o=i(N,o,M),z===null?_=N:z.sibling=N,z=N);return e&&T.forEach(function(_e){return t(r,_e)}),B&&dt(r,M),_}function D(r,o,m,h){if(typeof m=="object"&&m!==null&&m.type===Ma&&m.key===null&&(m=m.props.children),typeof m=="object"&&m!==null){switch(m.$$typeof){case pn:e:{for(var _=m.key;o!==null;){if(o.key===_){if(_=m.type,_===Ma){if(o.tag===7){a(r,o.sibling),h=n(o,m.props.children),h.return=r,r=h;break e}}else if(o.elementType===_||typeof _=="object"&&_!==null&&_.$$typeof===Gt&&na(_)===o.type){a(r,o.sibling),h=n(o,m.props),pl(h,m),h.return=r,r=h;break e}a(r,o);break}else t(r,o);o=o.sibling}m.type===Ma?(h=ca(m.props.children,r.mode,h,m.key),h.return=r,r=h):(h=Dn(m.type,m.key,m.props,null,r.mode,h),pl(h,m),h.return=r,r=h)}return u(r);case hl:e:{for(_=m.key;o!==null;){if(o.key===_)if(o.tag===4&&o.stateNode.containerInfo===m.containerInfo&&o.stateNode.implementation===m.implementation){a(r,o.sibling),h=n(o,m.children||[]),h.return=r,r=h;break e}else{a(r,o);break}else t(r,o);o=o.sibling}h=tu(m,r.mode,h),h.return=r,r=h}return u(r);case Gt:return m=na(m),D(r,o,m,h)}if(bl(m))return S(r,o,m,h);if(fl(m)){if(_=fl(m),typeof _!="function")throw Error(b(150));return m=_.call(m),x(r,o,m,h)}if(typeof m.then=="function")return D(r,o,Tn(m),h);if(m.$$typeof===pt)return D(r,o,Sn(r,m),h);xn(r,m)}return typeof m=="string"&&m!==""||typeof m=="number"||typeof m=="bigint"?(m=""+m,o!==null&&o.tag===6?(a(r,o.sibling),h=n(o,m),h.return=r,r=h):(a(r,o),h=eu(m,r.mode,h),h.return=r,r=h),u(r)):a(r,o)}return function(r,o,m,h){try{Xl=0;var _=D(r,o,m,h);return La=null,_}catch(T){if(T===ul||T===Ni)throw T;var z=je(29,T,null,r.mode);return z.lanes=h,z.return=r,z}finally{}}}var ma=hf(!0),bf=hf(!1),Nt=!1;function Kc(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function $u(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Qt(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Lt(e,t,a){var l=e.updateQueue;if(l===null)return null;if(l=l.shared,Y&2){var n=l.pending;return n===null?t.next=t:(t.next=n.next,n.next=t),l.pending=t,t=Wn(e),rf(e,null,a),t}return Gi(e,l,t,a),Wn(e)}function Gl(e,t,a){if(t=t.updateQueue,t!==null&&(t=t.shared,(a&4194048)!==0)){var l=t.lanes;l&=e.pendingLanes,a|=l,t.lanes=a,Rr(e,a)}}function lu(e,t){var a=e.updateQueue,l=e.alternate;if(l!==null&&(l=l.updateQueue,a===l)){var n=null,i=null;if(a=a.firstBaseUpdate,a!==null){do{var u={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};i===null?n=i=u:i=i.next=u,a=a.next}while(a!==null);i===null?n=i=t:i=i.next=t}else n=i=t;a={baseState:l.baseState,firstBaseUpdate:n,lastBaseUpdate:i,shared:l.shared,callbacks:l.callbacks},e.updateQueue=a;return}e=a.lastBaseUpdate,e===null?a.firstBaseUpdate=t:e.next=t,a.lastBaseUpdate=t}var ku=!1;function Nl(){if(ku){var e=Qa;if(e!==null)throw e}}function Ol(e,t,a,l){ku=!1;var n=e.updateQueue;Nt=!1;var i=n.firstBaseUpdate,u=n.lastBaseUpdate,c=n.shared.pending;if(c!==null){n.shared.pending=null;var s=c,f=s.next;s.next=null,u===null?i=f:u.next=f,u=s;var g=e.alternate;g!==null&&(g=g.updateQueue,c=g.lastBaseUpdate,c!==u&&(c===null?g.firstBaseUpdate=f:c.next=f,g.lastBaseUpdate=s))}if(i!==null){var v=n.baseState;u=0,g=f=s=null,c=i;do{var d=c.lane&-536870913,p=d!==c.lane;if(p?(H&d)===d:(l&d)===d){d!==0&&d===$a&&(ku=!0),g!==null&&(g=g.next={lane:0,tag:c.tag,payload:c.payload,callback:null,next:null});e:{var S=e,x=c;d=t;var D=a;switch(x.tag){case 1:if(S=x.payload,typeof S=="function"){v=S.call(D,v,d);break e}v=S;break e;case 3:S.flags=S.flags&-65537|128;case 0:if(S=x.payload,d=typeof S=="function"?S.call(D,v,d):S,d==null)break e;v=F({},v,d);break e;case 2:Nt=!0}}d=c.callback,d!==null&&(e.flags|=64,p&&(e.flags|=8192),p=n.callbacks,p===null?n.callbacks=[d]:p.push(d))}else p={lane:d,tag:c.tag,payload:c.payload,callback:c.callback,next:null},g===null?(f=g=p,s=v):g=g.next=p,u|=d;if(c=c.next,c===null){if(c=n.shared.pending,c===null)break;p=c,c=p.next,p.next=null,n.lastBaseUpdate=p,n.shared.pending=null}}while(!0);g===null&&(s=v),n.baseState=s,n.firstBaseUpdate=f,n.lastBaseUpdate=g,i===null&&(n.shared.lanes=0),Ft|=u,e.lanes=u,e.memoizedState=v}}function Sf(e,t){if(typeof e!="function")throw Error(b(191,e));e.call(t)}function Tf(e,t){var a=e.callbacks;if(a!==null)for(e.callbacks=null,e=0;ei?i:8;var u=G.T,c={};G.T=c,is(e,!1,t,a);try{var s=n(),f=G.S;if(f!==null&&f(c,s),s!==null&&typeof s=="object"&&typeof s.then=="function"){var g=f1(s,l);ql(e,t,g,Ye(e))}else ql(e,t,l,Ye(e))}catch(v){ql(e,t,{then:function(){},status:"rejected",reason:v},Ye())}finally{w.p=i,u!==null&&c.types!==null&&(u.types=c.types),G.T=u}}function v1(){}function ec(e,t,a,l){if(e.tag!==5)throw Error(b(476));var n=Kf(e).queue;Vf(e,n,t,ua,a===null?v1:function(){return Jf(e),a(l)})}function Kf(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:ua,baseState:ua,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:xt,lastRenderedState:ua},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:xt,lastRenderedState:a},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Jf(e){var t=Kf(e);t.next===null&&(t=e.alternate.memoizedState),ql(e,t.next.queue,{},Ye())}function ns(){return be($l)}function $f(){return ne().memoizedState}function kf(){return ne().memoizedState}function h1(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var a=Ye();e=Qt(a);var l=Lt(t,e,a);l!==null&&(Ne(l,t,a),Gl(l,t,a)),t={cache:Xc()},e.payload=t;return}t=t.return}}function b1(e,t,a){var l=Ye();a={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Di(e)?Ff(t,a):(a=Yc(e,t,a,l),a!==null&&(Ne(a,e,l),If(a,t,l)))}function Wf(e,t,a){var l=Ye();ql(e,t,a,l)}function ql(e,t,a,l){var n={lane:l,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(Di(e))Ff(t,n);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var u=t.lastRenderedState,c=i(u,a);if(n.hasEagerState=!0,n.eagerState=c,we(c,u))return Gi(e,t,n,0),V===null&&Ai(),!1}catch{}finally{}if(a=Yc(e,t,n,l),a!==null)return Ne(a,e,l),If(a,t,l),!0}return!1}function is(e,t,a,l){if(l={lane:2,revertLane:ps(),gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Di(e)){if(t)throw Error(b(479))}else t=Yc(e,a,l,2),t!==null&&Ne(t,e,2)}function Di(e){var t=e.alternate;return e===q||t!==null&&t===q}function Ff(e,t){Xa=ai=!0;var a=e.pending;a===null?t.next=t:(t.next=a.next,a.next=t),e.pending=t}function If(e,t,a){if(a&4194048){var l=t.lanes;l&=e.pendingLanes,a|=l,t.lanes=a,Rr(e,a)}}var Vl={readContext:be,use:qi,useCallback:ee,useContext:ee,useEffect:ee,useImperativeHandle:ee,useLayoutEffect:ee,useInsertionEffect:ee,useMemo:ee,useReducer:ee,useRef:ee,useState:ee,useDebugValue:ee,useDeferredValue:ee,useTransition:ee,useSyncExternalStore:ee,useId:ee,useHostTransitionStatus:ee,useFormState:ee,useActionState:ee,useOptimistic:ee,useMemoCache:ee,useCacheRefresh:ee};Vl.useEffectEvent=ee;var Pf={readContext:be,use:qi,useCallback:function(e,t){return Te().memoizedState=[e,t===void 0?null:t],e},useContext:be,useEffect:oo,useImperativeHandle:function(e,t,a){a=a!=null?a.concat([e]):null,Rn(4194308,4,wf.bind(null,t,e),a)},useLayoutEffect:function(e,t){return Rn(4194308,4,e,t)},useInsertionEffect:function(e,t){Rn(4,2,e,t)},useMemo:function(e,t){var a=Te();t=t===void 0?null:t;var l=e();if(pa){jt(!0);try{e()}finally{jt(!1)}}return a.memoizedState=[l,t],l},useReducer:function(e,t,a){var l=Te();if(a!==void 0){var n=a(t);if(pa){jt(!0);try{a(t)}finally{jt(!1)}}}else n=t;return l.memoizedState=l.baseState=n,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},l.queue=e,e=e.dispatch=b1.bind(null,q,e),[l.memoizedState,e]},useRef:function(e){var t=Te();return e={current:e},t.memoizedState=e},useState:function(e){e=Iu(e);var t=e.queue,a=Wf.bind(null,q,t);return t.dispatch=a,[e.memoizedState,a]},useDebugValue:as,useDeferredValue:function(e,t){var a=Te();return ls(a,e,t)},useTransition:function(){var e=Iu(!1);return e=Vf.bind(null,q,e.queue,!0,!1),Te().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,a){var l=q,n=Te();if(B){if(a===void 0)throw Error(b(407));a=a()}else{if(a=t(),V===null)throw Error(b(349));H&127||Mf(l,t,a)}n.memoizedState=a;var i={value:a,getSnapshot:t};return n.queue=i,oo(Gf.bind(null,l,i,e),[e]),l.flags|=2048,Wa(9,{destroy:void 0},Af.bind(null,l,i,a,t),null),a},useId:function(){var e=Te(),t=V.identifierPrefix;if(B){var a=at,l=tt;a=(l&~(1<<32-Be(l)-1)).toString(32)+a,t="_"+t+"R_"+a,a=li++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof l.is=="string"?u.createElement("select",{is:l.is}):u.createElement("select"),l.multiple?i.multiple=!0:l.size&&(i.size=l.size);break;default:i=typeof l.is=="string"?u.createElement(n,{is:l.is}):u.createElement(n)}}i[ve]=t,i[Oe]=l;e:for(u=t.child;u!==null;){if(u.tag===5||u.tag===6)i.appendChild(u.stateNode);else if(u.tag!==4&&u.tag!==27&&u.child!==null){u.child.return=u,u=u.child;continue}if(u===t)break e;for(;u.sibling===null;){if(u.return===null||u.return===t)break e;u=u.return}u.sibling.return=u.return,u=u.sibling}t.stateNode=i;e:switch(Se(i,n,l),n){case"button":case"input":case"select":case"textarea":l=!!l.autoFocus;break e;case"img":l=!0;break e;default:l=!1}l&&st(t)}}return $(t),fu(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,a),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==l&&st(t);else{if(typeof l!="string"&&t.stateNode===null)throw Error(b(166));if(e=Yt.current,Ta(t)){if(e=t.stateNode,a=t.memoizedProps,l=null,n=he,n!==null)switch(n.tag){case 27:case 5:l=n.memoizedProps}e[ve]=t,e=!!(e.nodeValue===a||l!==null&&l.suppressHydrationWarning===!0||Wd(e.nodeValue,a)),e||kt(t,!0)}else e=mi(e).createTextNode(l),e[ve]=t,t.stateNode=e}return $(t),null;case 31:if(a=t.memoizedState,e===null||e.memoizedState!==null){if(l=Ta(t),a!==null){if(e===null){if(!l)throw Error(b(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(b(557));e[ve]=t}else fa(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;$(t),e=!1}else a=au(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),e=!0;if(!e)return t.flags&256?(De(t),t):(De(t),null);if(t.flags&128)throw Error(b(558))}return $(t),null;case 13:if(l=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(n=Ta(t),l!==null&&l.dehydrated!==null){if(e===null){if(!n)throw Error(b(318));if(n=t.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(b(317));n[ve]=t}else fa(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;$(t),n=!1}else n=au(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),n=!0;if(!n)return t.flags&256?(De(t),t):(De(t),null)}return De(t),t.flags&128?(t.lanes=a,t):(a=l!==null,e=e!==null&&e.memoizedState!==null,a&&(l=t.child,n=null,l.alternate!==null&&l.alternate.memoizedState!==null&&l.alternate.memoizedState.cachePool!==null&&(n=l.alternate.memoizedState.cachePool.pool),i=null,l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(i=l.memoizedState.cachePool.pool),i!==n&&(l.flags|=2048)),a!==e&&a&&(t.child.flags|=8192),En(t,t.updateQueue),$(t),null);case 4:return Va(),e===null&&ys(t.stateNode.containerInfo),$(t),null;case 10:return ht(t.type),$(t),null;case 19:if(ye(le),l=t.memoizedState,l===null)return $(t),null;if(n=(t.flags&128)!==0,i=l.rendering,i===null)if(n)yl(l,!1);else{if(te!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(i=ti(e),i!==null){for(t.flags|=128,yl(l,!1),e=i.updateQueue,t.updateQueue=e,En(t,e),t.subtreeFlags=0,e=a,a=t.child;a!==null;)ff(a,e),a=a.sibling;return K(le,le.current&1|2),B&&dt(t,l.treeForkCount),t.child}e=e.sibling}l.tail!==null&&Re()>ci&&(t.flags|=128,n=!0,yl(l,!1),t.lanes=4194304)}else{if(!n)if(e=ti(i),e!==null){if(t.flags|=128,n=!0,e=e.updateQueue,t.updateQueue=e,En(t,e),yl(l,!0),l.tail===null&&l.tailMode==="hidden"&&!i.alternate&&!B)return $(t),null}else 2*Re()-l.renderingStartTime>ci&&a!==536870912&&(t.flags|=128,n=!0,yl(l,!1),t.lanes=4194304);l.isBackwards?(i.sibling=t.child,t.child=i):(e=l.last,e!==null?e.sibling=i:t.child=i,l.last=i)}return l.tail!==null?(e=l.tail,l.rendering=e,l.tail=e.sibling,l.renderingStartTime=Re(),e.sibling=null,a=le.current,K(le,n?a&1|2:a&1),B&&dt(t,l.treeForkCount),e):($(t),null);case 22:case 23:return De(t),Jc(),l=t.memoizedState!==null,e!==null?e.memoizedState!==null!==l&&(t.flags|=8192):l&&(t.flags|=8192),l?a&536870912&&!(t.flags&128)&&($(t),t.subtreeFlags&6&&(t.flags|=8192)):$(t),a=t.updateQueue,a!==null&&En(t,a.retryQueue),a=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(a=e.memoizedState.cachePool.pool),l=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(l=t.memoizedState.cachePool.pool),l!==a&&(t.flags|=2048),e!==null&&ye(sa),null;case 24:return a=null,e!==null&&(a=e.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),ht(se),$(t),null;case 25:return null;case 30:return null}throw Error(b(156,t.tag))}function _1(e,t){switch(Lc(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ht(se),Va(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Kn(t),null;case 31:if(t.memoizedState!==null){if(De(t),t.alternate===null)throw Error(b(340));fa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(De(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(b(340));fa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ye(le),null;case 4:return Va(),null;case 10:return ht(t.type),null;case 22:case 23:return De(t),Jc(),e!==null&&ye(sa),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return ht(se),null;case 25:return null;default:return null}}function fd(e,t){switch(Lc(t),t.tag){case 3:ht(se),Va();break;case 26:case 27:case 5:Kn(t);break;case 4:Va();break;case 31:t.memoizedState!==null&&De(t);break;case 13:De(t);break;case 19:ye(le);break;case 10:ht(t.type);break;case 22:case 23:De(t),Jc(),e!==null&&ye(sa);break;case 24:ht(se)}}function un(e,t){try{var a=t.updateQueue,l=a!==null?a.lastEffect:null;if(l!==null){var n=l.next;a=n;do{if((a.tag&e)===e){l=void 0;var i=a.create,u=a.inst;l=i(),u.destroy=l}a=a.next}while(a!==n)}}catch(c){L(t,t.return,c)}}function Wt(e,t,a){try{var l=t.updateQueue,n=l!==null?l.lastEffect:null;if(n!==null){var i=n.next;l=i;do{if((l.tag&e)===e){var u=l.inst,c=u.destroy;if(c!==void 0){u.destroy=void 0,n=t;var s=a,f=c;try{f()}catch(g){L(n,s,g)}}}l=l.next}while(l!==i)}}catch(g){L(t,t.return,g)}}function dd(e){var t=e.updateQueue;if(t!==null){var a=e.stateNode;try{Tf(t,a)}catch(l){L(e,e.return,l)}}}function md(e,t,a){a.props=ya(e.type,e.memoizedProps),a.state=e.memoizedState;try{a.componentWillUnmount()}catch(l){L(e,t,l)}}function Ul(e,t){try{var a=e.ref;if(a!==null){switch(e.tag){case 26:case 27:case 5:var l=e.stateNode;break;case 30:l=e.stateNode;break;default:l=e.stateNode}typeof a=="function"?e.refCleanup=a(l):a.current=l}}catch(n){L(e,t,n)}}function lt(e,t){var a=e.ref,l=e.refCleanup;if(a!==null)if(typeof l=="function")try{l()}catch(n){L(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(n){L(e,t,n)}else a.current=null}function pd(e){var t=e.type,a=e.memoizedProps,l=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":a.autoFocus&&l.focus();break e;case"img":a.src?l.src=a.src:a.srcSet&&(l.srcset=a.srcSet)}}catch(n){L(e,e.return,n)}}function du(e,t,a){try{var l=e.stateNode;K1(l,e.type,a,t),l[Oe]=t}catch(n){L(e,e.return,n)}}function yd(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Pt(e.type)||e.tag===4}function mu(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||yd(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Pt(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function ic(e,t,a){var l=e.tag;if(l===5||l===6)e=e.stateNode,t?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(e,t):(t=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,t.appendChild(e),a=a._reactRootContainer,a!=null||t.onclick!==null||(t.onclick=yt));else if(l!==4&&(l===27&&Pt(e.type)&&(a=e.stateNode,t=null),e=e.child,e!==null))for(ic(e,t,a),e=e.sibling;e!==null;)ic(e,t,a),e=e.sibling}function ui(e,t,a){var l=e.tag;if(l===5||l===6)e=e.stateNode,t?a.insertBefore(e,t):a.appendChild(e);else if(l!==4&&(l===27&&Pt(e.type)&&(a=e.stateNode),e=e.child,e!==null))for(ui(e,t,a),e=e.sibling;e!==null;)ui(e,t,a),e=e.sibling}function gd(e){var t=e.stateNode,a=e.memoizedProps;try{for(var l=e.type,n=t.attributes;n.length;)t.removeAttributeNode(n[0]);Se(t,l,a),t[ve]=e,t[Oe]=a}catch(i){L(e,e.return,i)}}var mt=!1,ce=!1,pu=!1,Eo=typeof WeakSet=="function"?WeakSet:Set,me=null;function z1(e,t){if(e=e.containerInfo,dc=vi,e=af(e),Hc(e)){if("selectionStart"in e)var a={start:e.selectionStart,end:e.selectionEnd};else e:{a=(a=e.ownerDocument)&&a.defaultView||window;var l=a.getSelection&&a.getSelection();if(l&&l.rangeCount!==0){a=l.anchorNode;var n=l.anchorOffset,i=l.focusNode;l=l.focusOffset;try{a.nodeType,i.nodeType}catch{a=null;break e}var u=0,c=-1,s=-1,f=0,g=0,v=e,d=null;t:for(;;){for(var p;v!==a||n!==0&&v.nodeType!==3||(c=u+n),v!==i||l!==0&&v.nodeType!==3||(s=u+l),v.nodeType===3&&(u+=v.nodeValue.length),(p=v.firstChild)!==null;)d=v,v=p;for(;;){if(v===e)break t;if(d===a&&++f===n&&(c=u),d===i&&++g===l&&(s=u),(p=v.nextSibling)!==null)break;v=d,d=v.parentNode}v=p}a=c===-1||s===-1?null:{start:c,end:s}}else a=null}a=a||{start:0,end:0}}else a=null;for(mc={focusedElem:e,selectionRange:a},vi=!1,me=t;me!==null;)if(t=me,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,me=e;else for(;me!==null;){switch(t=me,i=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(a=0;a title"))),Se(i,l,a),i[ve]=e,pe(i),l=i;break e;case"link":var u=Xo("link","href",n).get(l+(a.href||""));if(u){for(var c=0;cD&&(u=D,D=x,x=u);var r=Js(c,x),o=Js(c,D);if(r&&o&&(p.rangeCount!==1||p.anchorNode!==r.node||p.anchorOffset!==r.offset||p.focusNode!==o.node||p.focusOffset!==o.offset)){var m=v.createRange();m.setStart(r.node,r.offset),p.removeAllRanges(),x>D?(p.addRange(m),p.extend(o.node,o.offset)):(m.setEnd(o.node,o.offset),p.addRange(m))}}}}for(v=[],p=c;p=p.parentNode;)p.nodeType===1&&v.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof c.focus=="function"&&c.focus(),c=0;ca?32:a,G.T=null,a=sc,sc=null;var i=Zt,u=bt;if(re=0,Ia=Zt=null,bt=0,Y&6)throw Error(b(331));var c=Y;if(Y|=4,Ad(i.current),_d(i,i.current,u,a),Y=c,cn(0,!1),He&&typeof He.onPostCommitFiberRoot=="function")try{He.onPostCommitFiberRoot(Il,i)}catch{}return!0}finally{w.p=n,G.T=l,Ld(e,t)}}function Ao(e,t,a){t=Je(a,t),t=ac(e.stateNode,t,2),e=Lt(e,t,2),e!==null&&(en(e,2),ut(e))}function L(e,t,a){if(e.tag===3)Ao(e,e,a);else for(;t!==null;){if(t.tag===3){Ao(t,e,a);break}else if(t.tag===1){var l=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof l.componentDidCatch=="function"&&(Xt===null||!Xt.has(l))){e=Je(a,e),a=nd(2),l=Lt(t,a,2),l!==null&&(id(a,l,t,e),en(l,2),ut(l));break}}t=t.return}}function gu(e,t,a){var l=e.pingCache;if(l===null){l=e.pingCache=new G1;var n=new Set;l.set(t,n)}else n=l.get(t),n===void 0&&(n=new Set,l.set(t,n));n.has(a)||(fs=!0,n.add(a),e=D1.bind(null,e,t,a),t.then(e,e))}function D1(e,t,a){var l=e.pingCache;l!==null&&l.delete(t),e.pingedLanes|=e.suspendedLanes&a,e.warmLanes&=~a,V===e&&(H&a)===a&&(te===4||te===3&&(H&62914560)===H&&300>Re()-ji?!(Y&2)&&Pa(e,0):ds|=a,Fa===H&&(Fa=0)),ut(e)}function Zd(e,t){t===0&&(t=jr()),e=ba(e,t),e!==null&&(en(e,t),ut(e))}function j1(e){var t=e.memoizedState,a=0;t!==null&&(a=t.retryLane),Zd(e,a)}function C1(e,t){var a=0;switch(e.tag){case 31:case 13:var l=e.stateNode,n=e.memoizedState;n!==null&&(a=n.retryLane);break;case 19:l=e.stateNode;break;case 22:l=e.stateNode._retryCache;break;default:throw Error(b(314))}l!==null&&l.delete(t),Zd(e,a)}function R1(e,t){return Gc(e,t)}var ri=null,za=null,rc=!1,fi=!1,vu=!1,Bt=0;function ut(e){e!==za&&e.next===null&&(za===null?ri=za=e:za=za.next=e),fi=!0,rc||(rc=!0,B1())}function cn(e,t){if(!vu&&fi){vu=!0;do for(var a=!1,l=ri;l!==null;){if(e!==0){var n=l.pendingLanes;if(n===0)var i=0;else{var u=l.suspendedLanes,c=l.pingedLanes;i=(1<<31-Be(42|e)+1)-1,i&=n&~(u&~c),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(a=!0,Go(l,i))}else i=H,i=Ei(l,l===V?i:0,l.cancelPendingCommit!==null||l.timeoutHandle!==-1),!(i&3)||Pl(l,i)||(a=!0,Go(l,i));l=l.next}while(a);vu=!1}}function H1(){Vd()}function Vd(){fi=rc=!1;var e=0;Bt!==0&&$1()&&(e=Bt);for(var t=Re(),a=null,l=ri;l!==null;){var n=l.next,i=Kd(l,t);i===0?(l.next=null,a===null?ri=n:a.next=n,n===null&&(za=a)):(a=l,(e!==0||i&3)&&(fi=!0)),l=n}re!==0&&re!==5||cn(e),Bt!==0&&(Bt=0)}function Kd(e,t){for(var a=e.suspendedLanes,l=e.pingedLanes,n=e.expirationTimes,i=e.pendingLanes&-62914561;0c)break;var g=s.transferSize,v=s.initiatorType;g&&Do(v)&&(s=s.responseEnd,u+=g*(s"u"?null:document;function tm(e,t,a){var l=sl;if(l&&typeof t=="string"&&t){var n=Ke(t);n='link[rel="'+e+'"][href="'+n+'"]',typeof a=="string"&&(n+='[crossorigin="'+a+'"]'),wo.has(n)||(wo.add(n),e={rel:e,crossOrigin:a,href:t},l.querySelector(n)===null&&(t=l.createElement("link"),Se(t,"link",e),pe(t),l.head.appendChild(t)))}}function lp(e){zt.D(e),tm("dns-prefetch",e,null)}function np(e,t){zt.C(e,t),tm("preconnect",e,t)}function ip(e,t,a){zt.L(e,t,a);var l=sl;if(l&&e&&t){var n='link[rel="preload"][as="'+Ke(t)+'"]';t==="image"&&a&&a.imageSrcSet?(n+='[imagesrcset="'+Ke(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(n+='[imagesizes="'+Ke(a.imageSizes)+'"]')):n+='[href="'+Ke(e)+'"]';var i=n;switch(t){case"style":i=el(e);break;case"script":i=ol(e)}Fe.has(i)||(e=F({rel:"preload",href:t==="image"&&a&&a.imageSrcSet?void 0:e,as:t},a),Fe.set(i,e),l.querySelector(n)!==null||t==="style"&&l.querySelector(sn(i))||t==="script"&&l.querySelector(on(i))||(t=l.createElement("link"),Se(t,"link",e),pe(t),l.head.appendChild(t)))}}function up(e,t){zt.m(e,t);var a=sl;if(a&&e){var l=t&&typeof t.as=="string"?t.as:"script",n='link[rel="modulepreload"][as="'+Ke(l)+'"][href="'+Ke(e)+'"]',i=n;switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=ol(e)}if(!Fe.has(i)&&(e=F({rel:"modulepreload",href:e},t),Fe.set(i,e),a.querySelector(n)===null)){switch(l){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(on(i)))return}l=a.createElement("link"),Se(l,"link",e),pe(l),a.head.appendChild(l)}}}function cp(e,t,a){zt.S(e,t,a);var l=sl;if(l&&e){var n=Ba(l).hoistableStyles,i=el(e);t=t||"default";var u=n.get(i);if(!u){var c={loading:0,preload:null};if(u=l.querySelector(sn(i)))c.loading=5;else{e=F({rel:"stylesheet",href:e,"data-precedence":t},a),(a=Fe.get(i))&&gs(e,a);var s=u=l.createElement("link");pe(s),Se(s,"link",e),s._p=new Promise(function(f,g){s.onload=f,s.onerror=g}),s.addEventListener("load",function(){c.loading|=1}),s.addEventListener("error",function(){c.loading|=2}),c.loading|=4,wn(u,t,l)}u={type:"stylesheet",instance:u,count:1,state:c},n.set(i,u)}}}function sp(e,t){zt.X(e,t);var a=sl;if(a&&e){var l=Ba(a).hoistableScripts,n=ol(e),i=l.get(n);i||(i=a.querySelector(on(n)),i||(e=F({src:e,async:!0},t),(t=Fe.get(n))&&vs(e,t),i=a.createElement("script"),pe(i),Se(i,"link",e),a.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},l.set(n,i))}}function op(e,t){zt.M(e,t);var a=sl;if(a&&e){var l=Ba(a).hoistableScripts,n=ol(e),i=l.get(n);i||(i=a.querySelector(on(n)),i||(e=F({src:e,async:!0,type:"module"},t),(t=Fe.get(n))&&vs(e,t),i=a.createElement("script"),pe(i),Se(i,"link",e),a.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},l.set(n,i))}}function Qo(e,t,a,l){var n=(n=Yt.current)?pi(n):null;if(!n)throw Error(b(446));switch(e){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=el(a.href),a=Ba(n).hoistableStyles,l=a.get(t),l||(l={type:"style",instance:null,count:0,state:null},a.set(t,l)),l):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){e=el(a.href);var i=Ba(n).hoistableStyles,u=i.get(e);if(u||(n=n.ownerDocument||n,u={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,u),(i=n.querySelector(sn(e)))&&!i._p&&(u.instance=i,u.state.loading=5),Fe.has(e)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},Fe.set(e,a),i||rp(n,e,a,u.state))),t&&l===null)throw Error(b(528,""));return u}if(t&&l!==null)throw Error(b(529,""));return null;case"script":return t=a.async,a=a.src,typeof a=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=ol(a),a=Ba(n).hoistableScripts,l=a.get(t),l||(l={type:"script",instance:null,count:0,state:null},a.set(t,l)),l):{type:"void",instance:null,count:0,state:null};default:throw Error(b(444,e))}}function el(e){return'href="'+Ke(e)+'"'}function sn(e){return'link[rel="stylesheet"]['+e+"]"}function am(e){return F({},e,{"data-precedence":e.precedence,precedence:null})}function rp(e,t,a,l){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?l.loading=1:(t=e.createElement("link"),l.preload=t,t.addEventListener("load",function(){return l.loading|=1}),t.addEventListener("error",function(){return l.loading|=2}),Se(t,"link",a),pe(t),e.head.appendChild(t))}function ol(e){return'[src="'+Ke(e)+'"]'}function on(e){return"script[async]"+e}function Lo(e,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var l=e.querySelector('style[data-href~="'+Ke(a.href)+'"]');if(l)return t.instance=l,pe(l),l;var n=F({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return l=(e.ownerDocument||e).createElement("style"),pe(l),Se(l,"style",n),wn(l,a.precedence,e),t.instance=l;case"stylesheet":n=el(a.href);var i=e.querySelector(sn(n));if(i)return t.state.loading|=4,t.instance=i,pe(i),i;l=am(a),(n=Fe.get(n))&&gs(l,n),i=(e.ownerDocument||e).createElement("link"),pe(i);var u=i;return u._p=new Promise(function(c,s){u.onload=c,u.onerror=s}),Se(i,"link",l),t.state.loading|=4,wn(i,a.precedence,e),t.instance=i;case"script":return i=ol(a.src),(n=e.querySelector(on(i)))?(t.instance=n,pe(n),n):(l=a,(n=Fe.get(i))&&(l=F({},a),vs(l,n)),e=e.ownerDocument||e,n=e.createElement("script"),pe(n),Se(n,"link",l),e.head.appendChild(n),t.instance=n);case"void":return null;default:throw Error(b(443,t.type))}else t.type==="stylesheet"&&!(t.state.loading&4)&&(l=t.instance,t.state.loading|=4,wn(l,a.precedence,e));return t.instance}function wn(e,t,a){for(var l=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=l.length?l[l.length-1]:null,i=n,u=0;u title"):null)}function fp(e,t,a){if(a===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;switch(t.rel){case"stylesheet":return e=t.disabled,typeof t.precedence=="string"&&e==null;default:return!0}case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function lm(e){return!(e.type==="stylesheet"&&!(e.state.loading&3))}function dp(e,t,a,l){if(a.type==="stylesheet"&&(typeof l.media!="string"||matchMedia(l.media).matches!==!1)&&!(a.state.loading&4)){if(a.instance===null){var n=el(l.href),i=t.querySelector(sn(n));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=yi.bind(e),t.then(e,e)),a.state.loading|=4,a.instance=i,pe(i);return}i=t.ownerDocument||t,l=am(l),(n=Fe.get(n))&&gs(l,n),i=i.createElement("link"),pe(i);var u=i;u._p=new Promise(function(c,s){u.onload=c,u.onerror=s}),Se(i,"link",l),a.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(a,t),(t=a.state.preload)&&!(a.state.loading&3)&&(e.count++,a=yi.bind(e),t.addEventListener("load",a),t.addEventListener("error",a))}}var Eu=0;function mp(e,t){return e.stylesheets&&e.count===0&&Ln(e,e.stylesheets),0Eu?50:800)+t);return e.unsuspend=a,function(){e.unsuspend=null,clearTimeout(l),clearTimeout(n)}}:null}function yi(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Ln(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var gi=null;function Ln(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,gi=new Map,t.forEach(pp,e),gi=null,yi.call(e))}function pp(e,t){if(!(t.state.loading&4)){var a=gi.get(e);if(a)var l=a.get(null);else{a=new Map,gi.set(e,a);for(var n=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(fm)}catch(e){console.error(e)}}fm(),hr.exports=Ti;var xp=hr.exports;/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const dm=(...e)=>e.filter((t,a,l)=>!!t&&t.trim()!==""&&l.indexOf(t)===a).join(" ").trim();/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ep=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _p=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,a,l)=>l?l.toUpperCase():a.toLowerCase());/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Fo=e=>{const t=_p(e);return t.charAt(0).toUpperCase()+t.slice(1)};/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */var _u={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const zp=e=>{for(const t in e)if(t.startsWith("aria-")||t==="role"||t==="title")return!0;return!1},Mp=P.createContext({}),Ap=()=>P.useContext(Mp),Gp=P.forwardRef(({color:e,size:t,strokeWidth:a,absoluteStrokeWidth:l,className:n="",children:i,iconNode:u,...c},s)=>{const{size:f=24,strokeWidth:g=2,absoluteStrokeWidth:v=!1,color:d="currentColor",className:p=""}=Ap()??{},S=l??v?Number(a??g)*24/Number(t??f):a??g;return P.createElement("svg",{ref:s,..._u,width:t??f??_u.width,height:t??f??_u.height,stroke:e??d,strokeWidth:S,className:dm("lucide",p,n),...!i&&!zp(c)&&{"aria-hidden":"true"},...c},[...u.map(([x,D])=>P.createElement(x,D)),...Array.isArray(i)?i:[i]])});/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const J=(e,t)=>{const a=P.forwardRef(({className:l,...n},i)=>P.createElement(Gp,{ref:i,iconNode:t,className:dm(`lucide-${Ep(Fo(e))}`,`lucide-${e}`,l),...n}));return a.displayName=Fo(e),a};/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Np=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]],Op=J("arrow-right",Np);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const qp=[["circle",{cx:"18.5",cy:"17.5",r:"3.5",key:"15x4ox"}],["circle",{cx:"5.5",cy:"17.5",r:"3.5",key:"1noe27"}],["circle",{cx:"15",cy:"5",r:"1",key:"19l28e"}],["path",{d:"M12 17.5V14l-3-3 4-3 2 3h2",key:"1npguv"}]],mm=J("bike",qp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Up=[["path",{d:"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z",key:"hh9hay"}],["path",{d:"m3.3 7 8.7 5 8.7-5",key:"g66t2b"}],["path",{d:"M12 22V12",key:"d0xqtd"}]],bi=J("box",Up);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Dp=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],jp=J("check",Dp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cp=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],Io=J("chevron-down",Cp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Rp=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],Po=J("chevron-right",Rp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Hp=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],Bp=J("circle-alert",Hp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Yp=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],wp=J("circle-check",Yp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Qp=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}],["path",{d:"M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662",key:"154egf"}]],pm=J("circle-user",Qp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Lp=[["path",{d:"m18 16 4-4-4-4",key:"1inbqp"}],["path",{d:"m6 8-4 4 4 4",key:"15zrgr"}],["path",{d:"m14.5 4-5 16",key:"e7oirm"}]],Xp=J("code-xml",Lp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Zp=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],Vp=J("copy",Zp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Kp=[["rect",{width:"20",height:"14",x:"2",y:"5",rx:"2",key:"ynyp8z"}],["line",{x1:"2",x2:"22",y1:"10",y2:"10",key:"1b3vmo"}]],ym=J("credit-card",Kp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Jp=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 12a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1",key:"1oajmo"}],["path",{d:"M14 18a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1 1 1 0 0 1-1-1v-1a1 1 0 0 0-1-1",key:"mpwhp6"}]],er=J("file-braces",Jp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const $p=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],gm=J("file-text",$p);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const kp=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]],vm=J("house",kp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Wp=[["path",{d:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]],tr=J("layers",Wp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Fp=[["path",{d:"M9 17H7A5 5 0 0 1 7 7h2",key:"8i5ue5"}],["path",{d:"M15 7h2a5 5 0 1 1 0 10h-2",key:"1b9ql8"}],["line",{x1:"8",x2:"16",y1:"12",y2:"12",key:"1jonct"}]],hm=J("link-2",Fp);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ip=[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]],Pp=J("play",Ip);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ey=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],ty=J("search",ey);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ay=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],ar=J("server",ay);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ly=[["circle",{cx:"8",cy:"21",r:"1",key:"jimo8o"}],["circle",{cx:"19",cy:"21",r:"1",key:"13723u"}],["path",{d:"M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12",key:"9zh506"}]],bm=J("shopping-cart",ly);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ny=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],iy=J("terminal",ny);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const uy=[["path",{d:"M14 18V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v11a1 1 0 0 0 1 1h2",key:"wrbu53"}],["path",{d:"M15 18H9",key:"1lyqi6"}],["path",{d:"M19 18h2a1 1 0 0 0 1-1v-3.65a1 1 0 0 0-.22-.624l-3.48-4.35A1 1 0 0 0 17.52 8H14",key:"lysw3i"}],["circle",{cx:"17",cy:"18",r:"2",key:"332jqn"}],["circle",{cx:"7",cy:"18",r:"2",key:"19iecd"}]],Sm=J("truck",uy);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const cy=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],Tm=J("users",cy);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const sy=[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",key:"1ngwbx"}]],xm=J("wrench",sy);/** + * @license lucide-react v1.11.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const oy=[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]],lr=J("zap",oy),ry={users:Tm,orders:bm,tenants:vm,products:bi,locations:hm,partners:mm,deliveries:Sm,customers:pm,invoice:gm,payments:ym,utils:xm,mobile:bi};function fy({graphqlTopics:e,restTopics:t,activeTopic:a,setActiveTopic:l,searchQuery:n,setSearchQuery:i}){const[u,c]=P.useState({general:!0,graphql:!0,rest:!0}),s=g=>c(v=>({...v,[g]:!v[g]})),f=(g,v,d)=>y.jsxs("div",{children:[y.jsxs("button",{onClick:()=>s(d),className:"w-full flex items-center justify-between px-2 py-1.5 text-slate-800 font-semibold text-sm hover:text-brand-600 transition-colors group",children:[y.jsx("span",{className:"tracking-wide text-xs uppercase text-slate-400 group-hover:text-brand-500 transition-colors",children:v}),u[d]?y.jsx(Io,{size:14,className:"text-slate-400"}):y.jsx(Po,{size:14,className:"text-slate-400"})]}),y.jsx("div",{className:`mt-2 space-y-1 overflow-hidden transition-all duration-500 ${u[d]?"max-h-[800px] opacity-100":"max-h-0 opacity-0"}`,children:g.map(p=>{const S=(a==null?void 0:a.uniqueId)===p.uniqueId,x=ry[p.id]||tr;return y.jsxs("button",{onClick:()=>l(p),className:`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200 group ${S?"text-brand-700 bg-brand-50 shadow-sm font-medium":"text-slate-600 hover:text-slate-900 hover:bg-slate-100/50"}`,children:[y.jsx(x,{size:16,className:`${S?"text-brand-500":"text-slate-400 group-hover:text-slate-500"} transition-colors`}),p.name]},p.uniqueId)})})]});return y.jsxs("div",{className:"w-[280px] glass h-screen fixed top-0 left-0 flex flex-col z-20 transition-all",children:[y.jsxs("div",{className:"p-6 border-b border-slate-100/50",children:[y.jsxs("div",{className:"flex items-center gap-3 text-slate-900 font-bold text-xl mb-6",children:[y.jsx("div",{className:"w-8 h-8 rounded-lg bg-gradient-to-br from-brand-500 to-indigo-600 flex items-center justify-center shadow-glow",children:y.jsx(tr,{className:"text-white w-4 h-4"})}),y.jsx("span",{className:"tracking-tight",children:"NearleDaily"})]}),y.jsxs("div",{className:"relative group",children:[y.jsx(ty,{className:"w-4 h-4 absolute left-3 top-3 text-slate-400 group-focus-within:text-brand-500 transition-colors"}),y.jsx("input",{type:"text",className:"w-full pl-9 pr-3 py-2.5 bg-slate-50/50 border border-slate-200/60 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 focus:bg-white transition-all placeholder:text-slate-400",placeholder:"Search documentation...",value:n,onChange:g=>i(g.target.value)})]})]}),y.jsx("div",{className:"flex-1 overflow-y-auto py-6 px-4 scrollbar-hide",children:y.jsxs("nav",{className:"space-y-6",children:[y.jsxs("div",{children:[y.jsxs("button",{onClick:()=>s("general"),className:"w-full flex items-center justify-between px-2 py-1.5 text-slate-800 font-semibold text-sm hover:text-brand-600 transition-colors group",children:[y.jsx("span",{className:"tracking-wide text-xs uppercase text-slate-400 group-hover:text-brand-500 transition-colors",children:"Getting Started"}),u.general?y.jsx(Io,{size:14,className:"text-slate-400"}):y.jsx(Po,{size:14,className:"text-slate-400"})]}),y.jsx("div",{className:`mt-2 space-y-1 overflow-hidden transition-all duration-300 ${u.general?"max-h-40 opacity-100":"max-h-0 opacity-0"}`,children:y.jsxs("button",{onClick:()=>l(null),className:`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200 ${a?"text-slate-600 hover:text-slate-900 hover:bg-slate-100/50":"text-brand-700 bg-brand-50 shadow-sm font-medium"}`,children:[y.jsx(iy,{size:16,className:a?"text-slate-400":"text-brand-500"}),"Introduction"]})})]}),e.length>0&&f(e,"GraphQL","graphql"),t.length>0&&f(t,"REST API","rest")]})})]})}const dy={getsubcategory:{query:` + query GetSubCategory($moduleid: bigint!, $categoryid: bigint!) { + app_subcategory( + where: { + categoryid: { _eq: $categoryid } + category: { modules: { moduleid: { _eq: $moduleid } } } + } + ) { + subcategoryid + categoryid + categorytypeid + subcategoryname + categoryname + sortorder + status + statuscode + } + } + `,variables:`{ + "moduleid": 6, + "categoryid": 1 +}`},getorders:{query:` + query GetOrders( + $start: timestamptz! + $end: timestamptz! + $status: String! + $limit: Int! + $offset: Int! + ) { + orders( + where: { + deliverytime: { _gte: $start, _lte: $end } + orderstatus: { _eq: $status } + } + limit: $limit + offset: $offset + ) { + orderheaderid + orderid + orderstatus + deliverytime + orderamount + tenant { + tenantname + } + } + } + `,variables:`{ + "start": "2026-01-01T00:00:00", + "end": "2026-01-31T23:59:59", + "status": "delivered", + "limit": 10, + "offset": 0 +}`},gettenantlocations:{query:` + query GetTenantLocations($tenantid: bigint!) { + tenant_locations(where: { tenantid: { _eq: $tenantid } }) { + locationid + locationname + tenantid + } + } + `,variables:`{ + "tenantid": 1 +}`},getapplocations:{query:` + query GetAppLocations($userid: bigint!) { + details: app_location( + where: { + app_locationconfigs: { + status: { _eq: "Active" } + userid: { _eq: $userid } + } + } + ) { + applocationid + locationname + } + } + `,variables:`{ + "userid": 1 +}`},getusers:{query:` + query GetUsers { + app_user { + userid + username + email + contactno + status + } + } + `,variables:"{}"},gettenantinfo:{query:` + query GetTenantInfo($tenantid: bigint!) { + tenants(where: { tenantid: { _eq: $tenantid } }) { + tenantid + tenantname + email + contactno + status + } + } + `,variables:`{ + "tenantid": 1079, + "configid": 1, + "fromdate": "2025-07-24T00:00:00", + "todate": "2025-07-24T23:59:59" +}`},getordersummary:{query:` + query GetOrderSummary( + $tenantid: bigint! + $configid: bigint! + $fromdate: timestamp! + $todate: timestamp! + ) { + orders_aggregate( + where: { + tenantid: { _eq: $tenantid } + deliverytime: { _gte: $fromdate, _lte: $todate } + } + ) { + aggregate { + count + } + } + orders( + where: { + tenantid: { _eq: $tenantid } + deliverytime: { _gte: $fromdate, _lte: $todate } + } + limit: 10 + order_by: { deliverytime: desc } + ) { + orderid + orderstatus + orderamount + deliverytime + } + } + `,variables:`{ + "tenantid": 1079, + "fromdate": "2025-07-24T00:00:00", + "todate": "2025-07-24T23:59:59" +}`},getcustomersbytenant:{query:` + query GetCustomersByTenant( + $tenantid: bigint! + $limit: Int! + $offset: Int! + ) { + tenantcustomers( + where: { tenantid: { _eq: $tenantid } } + limit: $limit + offset: $offset + order_by: { customer: { customerid: desc } } + ) { + tenantlocationid: locationid + customer { + customerid + firstname + lastname + contactno + email + address + suburb + city + state + landmark + doorno + postcode + latitude + longitude + applocationid + status + } + } + } + `,variables:`{ + "tenantid": 1079, + "limit": 10, + "offset": 0 +}`},getapproles:{query:` + query GetAppRoles($configid: bigint!) { + app_roles(where: { configid: { _eq: $configid } }) { + roleid + rolename + configid + } + } + `,variables:`{ + "configid": 1 +}`},getactivelocationbyid:{query:` + query GetActiveLocationById { + app_locations(where: { status: { _eq: "Active" } }) { + locationid + locationname + } + } + `,variables:"{}"},getlocationsconfig:{query:` + query GetLocations { + details: app_location(where: {status: {_eq: "Active"}}) { + applocationid + locationname + image + city + state + postcode + latitude + longitude + opentime + closetime + radius + applocationadmins: app_locationconfigs(where: {notify: {_eq: "true"}}) { + applocationid + userid + notify + app_user { + userfcmtokem: userfcmtoken + } + } + } + } + `,variables:"{}"},getpartners:{query:` + query GetPartners( + $applocationid: bigint! + $partnerid: bigint! + $limit: Int! + $offset: Int! + ) { + details: partnerinfo( + where: { + status: { _eq: "Active" } + _and: [ + { + _or: [ + { applocationid: { _eq: $applocationid } } + { applocationid: { _eq: 0 } } + ] + } + { + _or: [ + { partnerid: { _eq: $partnerid } } + { partnerid: { _eq: 0 } } + ] + } + ] + } + limit: $limit + offset: $offset + ) { + partnerid + applocationid + partnertypeid + partnername + primarycontact + primaryemail + contactno + address + suburb + state + city + partnerimage + } + } + `,variables:`{ + "applocationid": 1, + "partnerid": 0, + "limit": 10, + "offset": 0 +}`},getridershifts:{query:` + query GetRiderShifts($applocationid: bigint!) { + details: ridershifts( + where: { applocationid: { _eq: $applocationid } } + order_by: { shiftid: desc } + ) { + shiftid + shiftdate + starttime + endtime + shifthours + basefare + additionalkm + additionalcharges + orders + fuelcharge + shiftname + } + } + `,variables:`{ + "applocationid": 1 +}`},getapptypes:{query:` + query GetTypes($tag: String!) { + app_types(where: { status: { _eq: "Active" }, tag: { _eq: $tag } }) { + apptypeid + typename + tag + status + description + mapid + created + updated + } + } + `,variables:`{ + "tag": "partner" +}`},gettenantcustomers:{query:` + query GetTenantCustomers( + $tenantid: bigint! + $locationid: bigint! + $limit: Int! + $offset: Int! + ) { + details: tenantcustomers( + where: { + tenantid: { _eq: $tenantid } + locationid: { _eq: $locationid } + customer: { customerid: { _is_null: false } } + } + limit: $limit + offset: $offset + order_by: { customer: { customerid: desc } } + ) { + tenantlocationid: locationid + customer { + customerid + firstname + lastname + contactno + email + address + suburb + city + state + landmark + doorno + postcode + latitude + longitude + applocationid + status + } + } + } + `,variables:`{ + "tenantid": 1079, + "locationid": 1, + "limit": 10, + "offset": 0 +}`},getproductcategories:{query:` + query GetProductCategories($moduleid: bigint!) { + productcategories( + where: { moduleid: { _eq: $moduleid }, status: { _eq: "Active" } } + order_by: { sortorder: asc } + ) { + categoryid + moduleid + categorytypeid + categoryname + status + created + updated + } + } + `,variables:`{ + "moduleid": 6 +}`},getproductsubcategories:{query:` + query GetProductSubCategories($categoryid: bigint!) { + product_subcategories(where: { categoryid: { _eq: $categoryid } }) { + subcategoryid + categoryid + subcategoryname + status + } + } + `,variables:`{ + "categoryid": 1 +}`},getproductvariants:{query:` + query GetProductVariants($tenantid: bigint!, $subcategoryid: bigint!) { + productvariants( + where: { + tenantid: { _eq: $tenantid } + subcategoryid: { _eq: $subcategoryid } + } + ) { + variantid + productid + tenantid + categoryid + subcategoryid + variantname + price + status + created + updated + category { + categoryname + } + } + } + `,variables:`{ + "tenantid": 1079, + "subcategoryid": 1 +}`},getstockstatement:{query:` + query GetStockStatement( + $tenantid: bigint! + $locationid: bigint! + $subcategoryid: bigint + $keyword: String + $limit: Int + $offset: Int + ) { + product_stock_statement( + where: { + tenantid: { _eq: $tenantid } + locationid: { _eq: $locationid } + subcategoryid: { _eq: $subcategoryid } + productname: { _ilike: $keyword } + } + limit: $limit + offset: $offset + order_by: { productid: desc } + ) { + productid + productname + productimage + categoryid + subcategoryid + productunit + unitvalue + productcost + taxpercent + taxamount + retailprice + tenantid + locationid + opening + credit + debit + closing + } + } + `,variables:`{ + "tenantid": 1079, + "locationid": 1, + "subcategoryid": null, + "keyword": "%", + "limit": 10, + "offset": 0 +}`},gettenantdeliveries:{query:` + query GetTenantDeliveriesFull( + $tenantid: bigint! + $status: String + $fromdate: timestamp + $todate: timestamp + $keyword: String + $limit: Int + $offset: Int + ) { + deliveries( + where: { + tenantid: { _eq: $tenantid } + _and: [ + { orderstatus: { _eq: $status } } + { deliverydate: { _gte: $fromdate } } + { deliverydate: { _lte: $todate } } + { + _or: [ + { pickupcustomer: { _ilike: $keyword } } + { deliverycustomer: { _ilike: $keyword } } + { pickupcontactno: { _ilike: $keyword } } + { deliverycontactno: { _ilike: $keyword } } + { orderid: { _ilike: $keyword } } + ] + } + ] + } + limit: $limit + offset: $offset + order_by: { deliveryid: desc } + ) { + deliveryid + orderid + deliverydate + orderstatus + pickupcustomer + pickupcontactno + pickupaddress + deliverycustomer + deliverycontactno + deliveryaddress + kms + customers { + customertoken + } + app_users { + firstname + contactno + } + tenants { + tenantname + primarycontact + } + } + } + `,variables:`{ + "tenantid": 1079, + "status": "delivered", + "fromdate": "2026-01-01T00:00:00", + "todate": "2026-01-31T23:59:59", + "keyword": "%", + "limit": 10, + "offset": 0 +}`},getinvoiceinsight:{query:` + query GetInvoiceInsight($tenantid: bigint!) { + invoice_insight(where: { tenantid: { _eq: $tenantid } }) { + totalcount + total + pendingcount + pending + pendingpercent + confirmedcount + confirmed + confirmedpercent + paidcount + paid + paidpercent + overduecount + overdue + overduepercent + } + } + `,variables:`{ + "tenantid": 1079 +}`},getproductscount:{query:` + query GetProductsCount( + $tenantid: bigint! + $categoryid: bigint! + $subcategoryid: bigint! + ) { + total: products_aggregate( + where: { + tenantid: { _eq: $tenantid } + categoryid: { _eq: $categoryid } + subcategoryid: { _eq: $subcategoryid } + } + ) { + aggregate { + count + } + } + available: products_aggregate( + where: { + tenantid: { _eq: $tenantid } + categoryid: { _eq: $categoryid } + subcategoryid: { _eq: $subcategoryid } + productstatus: { _eq: "available" } + } + ) { + aggregate { + count + } + } + outofstock: products_aggregate( + where: { + tenantid: { _eq: $tenantid } + categoryid: { _eq: $categoryid } + subcategoryid: { _eq: $subcategoryid } + productstatus: { _eq: "outofstock" } + } + ) { + aggregate { + count + } + } + } + `,variables:`{ + "tenantid": 1079, + "categoryid": 1, + "subcategoryid": 1 +}`},createproduct:{query:` + mutation CreateProduct($object: products_insert_input!) { + insert_products_one(object: $object) { + productid + applocationid + tenantid + categoryid + subcategoryid + productname + productimage + productdesc + productsku + productbrand + productunit + unitvalue + toppicks + productcost + taxamount + taxpercent + producttax + productstock + productcombo + variants + quantity + retailprice + diffprice + diffpercent + othercost + approve + productstatus + } + } + `,variables:`{ + "object": { + "applocationid": 1, + "tenantid": 1079, + "categoryid": 1, + "subcategoryid": 1, + "productname": "Sample Product", + "productimage": "", + "productdesc": "Sample description", + "productsku": "SKU123", + "productbrand": "BrandX", + "productunit": "kg", + "unitvalue": 1, + "toppicks": false, + "productcost": 50, + "taxamount": 5, + "taxpercent": 10, + "producttax": true, + "productstock": 100, + "productcombo": false, + "variants": false, + "quantity": 100, + "retailprice": 60, + "diffprice": 10, + "diffpercent": 20, + "othercost": 0, + "approve": true, + "productstatus": "available" + } + }`},getinvoices:{query:` + query GetInvoices($tenantid: bigint!, $billstatus: bigint!) { + tenantsales( + where: { + tenantid: { _eq: $tenantid } + billstatus: { _eq: $billstatus } + } + order_by: { salesid: desc } + ) { + salesid + tenantid + totalamount + billstatus + duedate + status + } + } + `,variables:`{ + "tenantid": 1079, + "billstatus": 1 + }`},getcustomerlocations:{query:` + query GetCustomerLocations($customerid: bigint!) { + customer_locations(where: { customerid: { _eq: $customerid } }) { + locationid + latitude + longitude + address + } + } + `,variables:`{ + "customerid": 6060 +}`},getcustomerordersv3:{query:` + query GetCustomerOrders($customerid: bigint!, $tenantid: bigint!, $moduleid: bigint!, $fromdate: timestamptz!, $todate: timestamptz!, $orderstatus: String!, $keyword: String, $limit: Int!, $offset: Int!) { + orders( + where: { + customerid: { _eq: $customerid } + tenantid: { _eq: $tenantid } + moduleid: { _eq: $moduleid } + orderstatus: { _eq: $orderstatus } + orderdate: { _gte: $fromdate, _lte: $todate } + _or: [{ orderid: { _ilike: $keyword } }] + } + limit: $limit + offset: $offset + ) { + orderid + orderstatus + orderamount + } + } + `,variables:`{ + "customerid": 6060, + "tenantid": 1087, + "moduleid": 2, + "fromdate": "2026-01-01T00:00:00", + "todate": "2026-12-31T23:59:59", + "orderstatus": "delivered", + "keyword": "%pizza%", + "limit": 10, + "offset": 0 +}`},getcustomer:{query:` + query GetCustomer($customerid: bigint!) { + customers(where: { customerid: { _eq: $customerid } }) { + customerid + name + contactno + } + } + `,variables:`{ + "customerid": 6060 +}`},getcustomerrequests:{query:` + query GetCustomerRequests($customerid: bigint!, $limit: Int!, $offset: Int!) { + customer_requests(where: { customerid: { _eq: $customerid } }, limit: $limit, offset: $offset) { + requestid + status + } + } + `,variables:`{ + "customerid": 6060, + "limit": 10, + "offset": 0 +}`},getmobileproductsubcategories:{query:` + query GetProductSubcategories($categoryid: bigint!) { + app_subcategory(where: { categoryid: { _eq: $categoryid } }) { + subcategoryid + subcategoryname + } + } + `,variables:`{ + "categoryid": 1001 +}`},getmobileappcategories:{query:` + query GetAppCategories { + app_category { + categoryid + categoryname + } + } + `,variables:"{}"},getmobileproductvariants:{query:` + query GetProductVariants($tenantid: bigint!, $subcategoryid: bigint!) { + product_variants(where: { tenantid: { _eq: $tenantid }, subcategoryid: { _eq: $subcategoryid } }) { + variantid + productname + price + } + } + `,variables:`{ + "tenantid": 1087, + "subcategoryid": 14 +}`},gettenantpromotions:{query:` + query GetTenantPromotions($tenantid: bigint!, $locationid: bigint!) { + promotions(where: { tenantid: { _eq: $tenantid }, locationid: { _eq: $locationid } }) { + promotionid + title + } + } + `,variables:`{ + "tenantid": 1087, + "locationid": 1 +}`},getappconfig:{query:` + query GetAppConfig($configid: bigint!) { + app_config(where: { configid: { _eq: $configid } }) { + configkey + configvalue + } + } + `,variables:`{ + "configid": 15 +}`},searchcustomers:{query:` + query SearchCustomers($tenantid: bigint!, $keyword: String!) { + customers(where: { tenantid: { _eq: $tenantid }, name: { _ilike: $keyword } }) { + customerid + name + } + } + `,variables:`{ + "tenantid": 1087, + "keyword": "%john%" +}`},gettenantorders:{query:` + query GetTenantOrders { + orders { + orderid + tenantid + } + } + `,variables:"{}"},getstaff:{query:` + query GetStaff($tenantid: bigint!) { + staff(where: { tenantid: { _eq: $tenantid } }) { + staffid + name + } + } + `,variables:`{ + "tenantid": 1087 +}`},getmobileapplocations:{query:` + query GetAppLocations { + app_location { + applocationid + locationname + } + } + `,variables:"{}"}},Em="https://api.workolik.com",my=[{id:"users",name:"Users",description:"Manage users and roles within the NearleDaily ecosystem.",endpoints:[{name:"getusers",method:"GET",url:"/api/rest/getusers?roleid=1&tenantid=1079&limit=10&offset=0",description:"Retrieve a list of all users in the system."},{name:"getapproles",method:"GET",url:"/api/rest/getapproles?configid=1",description:"Get all application roles based on a specific configuration."}]},{id:"orders",name:"Orders",description:"Endpoints related to creating, updating, and querying customer orders.",endpoints:[{name:"getorders",method:"GET",url:"/api/rest/getorders?start=2026-01-01T00:00:00&end=2026-01-31T23:59:59&status=delivered&limit=10&offset=0",description:"Get detailed order information within a time frame."},{name:"getordersummary",method:"GET",url:"/api/rest/getordersummary?tenantid=1079&configid=1&fromdate=2025-07-24T00:00:00&todate=2025-07-24T23:59:59",description:"Retrieve high-level summary and aggregated counts for orders."}]},{id:"tenants",name:"Tenants",description:"Manage tenant details, their customers, and their specific delivery statistics.",endpoints:[{name:"gettenantinfo",method:"GET",url:"/api/rest/gettenantinfo?tenantid=1079",description:"Get specific information about a tenant by their ID."},{name:"gettenantlocations",method:"GET",url:"/api/rest/gettenantlocations?tenantid=1",description:"Get all physical locations linked to a tenant."},{name:"getcustomersbytenant",method:"GET",url:"/api/rest/getcustomersbytenant?tenantid=1079&limit=10&offset=0",description:"Retrieve customers associated with a specific tenant."},{name:"gettenantcustomers",method:"GET",url:"/api/rest/gettenantcustomers?tenantid=1079&locationid=1&limit=10&offset=0",description:"Get customers under a specific tenant and location combination."},{name:"gettenantdeliveries",method:"GET",url:"/api/rest/gettenantdeliveries?tenantid=1079&status=delivered&fromdate=2026-01-01T00:00:00&todate=2026-01-31T23:59:59&keyword=%25&limit=10&offset=0",description:"Query extensive delivery data for a tenant including pickup/delivery info."},{name:"getinvoiceinsight",method:"GET",url:"/api/rest/getinvoiceinsight?tenantid=1079",useGraphql:!0,description:"Retrieve detailed insights and statistics regarding tenant invoices."},{name:"getinvoices",method:"GET",url:"/api/rest/getinvoices?tenantid=1079&billstatus=1",useGraphql:!0,description:"Retrieve all invoices for a tenant based on their billing status."}]},{id:"products",name:"Products",description:"Operations for managing product catalogs, categories, variants, and stock tracking.",endpoints:[{name:"getproductcategories",method:"GET",url:"/api/rest/getproductcategories?moduleid=6",description:"Get all root product categories for a specific module."},{name:"getsubcategory",method:"GET",url:"/api/rest/getsubcategory?moduleid=6&categoryid=1",description:"Get a specific subcategory belonging to a root category."},{name:"getproductsubcategories",method:"GET",url:"/api/rest/getproductsubcategories?categoryid=1",description:"List all subcategories under a specific root category."},{name:"getproductvariants",method:"GET",url:"/api/rest/getproductvariants?tenantid=1079&subcategoryid=1",description:"Get different variants of products (e.g. sizes, colors) for a tenant."},{name:"getstockstatement",method:"GET",url:"/api/rest/getstockstatement?tenantid=1079&locationid=1&subcategoryid=&keyword=%25&limit=10&offset=0",description:"Generate a comprehensive statement of stock including opening, credit, debit, closing balances."},{name:"getproductscount",method:"GET",url:"/api/rest/getproductscount?tenantid=1079&categoryid=1&subcategoryid=1",description:"Get aggregated counts of products available and out of stock."},{name:"createproduct",method:"POST",url:"/api/rest/createproduct",useGraphql:!0,description:"Create a new product within the catalog."}]},{id:"locations",name:"Apps & Locations",description:"Query configuration endpoints for application locations and active statuses.",endpoints:[{name:"getapplocations",method:"GET",url:"/api/rest/getapplocations?userid=1",useGraphql:!0,description:"Retrieve application location settings for a specific user."},{name:"getactivelocationbyid",method:"GET",url:"/api/rest/getapplocations",description:"List all currently active locations globally."},{name:"getlocationsconfig",method:"GET",url:"/api/rest/getapplocationconfig",description:"Retrieve the global configuration properties for application locations."},{name:"getapptypes",method:"GET",url:"/api/rest/getapptypes?tag=partner",description:"Get specific application types grouped by a tag name."}]},{id:"partners",name:"Partners",description:"Manage partners, drivers/riders, and their shifts and earnings.",endpoints:[{name:"getpartners",method:"GET",url:"/api/rest/getpartners?applocationid=1&partnerid=0&limit=10&offset=0",description:"Retrieve a list of active partners associated with locations."},{name:"getridershifts",method:"GET",url:"/api/rest/getridershifts?applocationid=1",description:"Get historic and active shift records for riders in a specific location."}]},{id:"mobile",name:"Mobile",description:"Specific endpoints and GraphQL queries optimized for mobile application integration.",endpoints:[{name:"getcustomerlocations",method:"GET",url:"/api/rest/getcustomerlocations?customerid=6060",description:"Retrieve physical locations associated with a specific customer."},{name:"getcustomerordersv3",method:"GET",url:"/api/rest/getcustomerordersv3?customerid=6060&tenantid=1087&moduleid=2&fromdate=2026-01-01T00:00:00&todate=2026-12-31T23:59:59&orderstatus=delivered&keyword=%25pizza%25&limit=10&offset=0",description:"Fetch comprehensive order history for a customer with advanced filtering."},{name:"getcustomer",method:"GET",url:"/api/rest/getcustomer?customerid=6060",description:"Get profile details for a specific customer."},{name:"getcustomerrequests",method:"GET",url:"/api/rest/getcustomerrequests?customerid=6060&limit=10&offset=0",description:"List all service requests made by a customer."},{name:"getmobileproductsubcategories",method:"GET",url:"/api/rest/getmobileproductsubcategories?categoryid=1001",description:"Retrieve subcategories under a specific product category for mobile display."},{name:"getmobileappcategories",method:"GET",url:"/api/rest/getmobileappcategories",description:"Fetch all available application categories."},{name:"getmobileproductvariants",method:"GET",url:"/api/rest/getmobileproductvariants?tenantid=1087&subcategoryid=14",description:"Get product variants filtered by tenant and subcategory."},{name:"gettenantpromotions",method:"GET",url:"/api/rest/gettenantpromotions?tenantid=1087&locationid=1",description:"Retrieve active promotions for a specific tenant location."},{name:"getappconfig",method:"GET",url:"/api/rest/getappconfig?configid=15",description:"Retrieve specific application configuration settings."},{name:"searchcustomers",method:"GET",url:"/api/rest/searchcustomers?tenantid=1087&keyword=%25john%25",description:"Search for customers by name within a tenant's scope."},{name:"gettenantorders",method:"GET",url:"/api/rest/gettenantorders",description:"List orders across tenants (Admin level)."},{name:"getstaff",method:"GET",url:"/api/rest/getstaff?tenantid=1087",description:"Retrieve staff members associated with a specific tenant."},{name:"gettenantinfo",method:"GET",url:"/api/rest/gettenantinfo?tenantid=1079",description:"Get basic information about a tenant."},{name:"gettenantlocations",method:"GET",url:"/api/rest/gettenantlocations?tenantid=1",description:"Fetch all locations for a given tenant."},{name:"getmobileapplocations",method:"GET",url:"/api/rest/getmobileapplocations",description:"Retrieve all application-wide locations."},{name:"getsubcategory",method:"GET",url:"/api/rest/getsubcategory?moduleid=6&categoryid=1",description:"Get detailed subcategory info."},{name:"getpartners",method:"GET",url:"/api/rest/getpartners?applocationid=1&partnerid=44&limit=10&offset=0",description:"Retrieve partner details for mobile integration."},{name:"getlocationsconfig",method:"GET",url:"/api/rest/getlocationsconfig",useGraphql:!0,description:"Get location configuration settings."}]}],py=/("(?:\\u[a-fA-F0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(?:true|false|null)\b|-?\d+(?:\.\d+)?(?:[eE][+\-]?\d+)?)/g;function yy(e){return e.replace(/&/g,"&").replace(//g,">")}function nr(e){let t;try{t=JSON.stringify(e,null,2)}catch{t=String(e)}return typeof t!="string"&&(t=String(t)),yy(t).replace(py,a=>{let l="text-amber-300";return/^"/.test(a)?l=/:$/.test(a)?"text-sky-300":"text-emerald-300":a==="true"||a==="false"?l="text-violet-300":a==="null"&&(l="text-rose-300"),`${a}`})}function gy(e){try{return decodeURIComponent(e)}catch{return e}}function ir(e){const[,t=""]=e.split("?"),a={};if(t)for(const l of t.split("&")){const[n,i=""]=l.split("=");n&&(a[n]=gy(i))}return a}function vy({endpoint:e,topic:t}){const a=t.type==="rest",l=a?null:dy[e.name],[n,i]=P.useState((l==null?void 0:l.query)||""),[u,c]=P.useState((l==null?void 0:l.variables)||"{}"),[s,f]=P.useState(()=>ir(e.url)),[g,v]=P.useState(null),[d,p]=P.useState(!1),[S,x]=P.useState(null),[D,r]=P.useState(!1);P.useEffect(()=>{i((l==null?void 0:l.query)||""),c((l==null?void 0:l.variables)||"{}"),f(ir(e.url)),v(null),x(null)},[e.name]);const o=async()=>{if(g)try{await navigator.clipboard.writeText(JSON.stringify(g.data,null,2)),r(!0),setTimeout(()=>r(!1),1500)}catch{}},m=async()=>{x(null),p(!0),v(null);try{if(a){const z=e.url.split("?")[0],T=e.method==="GET";let M=t.baseUrl+e.url;if(T&&Object.keys(s).length>0){const Mt=new URLSearchParams(s).toString();M=t.baseUrl+z+(Mt?"?"+Mt:"")}const A={method:e.method,headers:{"Content-Type":"application/json"}};!T&&e.body&&(A.body=typeof e.body=="string"?e.body:JSON.stringify(e.body));const N=await fetch(M,A),ie=await N.text();let _e;try{_e=JSON.parse(ie)}catch{_e=ie}v({status:N.status,ok:N.ok,data:_e})}else{const z=t.baseUrl;let T=z+e.url;const M={method:e.method,headers:{"x-hasura-admin-secret":"nearle-admin-secret","Content-Type":"application/json"}};if(e.method==="GET"&&!e.useGraphql){const ie=Object.entries(s).filter(([,rl])=>String(rl).trim()==="").map(([rl])=>rl);if(ie.length){x("Required parameter(s): "+ie.join(", ")),p(!1);return}const _e=e.url.split("?")[0],Mt=new URLSearchParams(s).toString();T=z+_e+(Mt?"?"+Mt:"")}else{const ie=u!=null&&u.trim()?JSON.parse(u):{};T=z+"/v1/graphql",M.method="POST",M.body=JSON.stringify({query:n,variables:ie})}const A=await fetch(T,M),N=await A.json();v({status:A.status,ok:A.ok,data:N})}}catch(z){x(String(z))}finally{p(!1)}},h={GET:"bg-emerald-100/50 text-emerald-700 border-emerald-200",POST:"bg-blue-100/50 text-blue-700 border-blue-200",PUT:"bg-amber-100/50 text-amber-700 border-amber-200",DELETE:"bg-red-100/50 text-red-700 border-red-200",PATCH:"bg-purple-100/50 text-purple-700 border-purple-200"}[e.method]||"bg-slate-100/50 text-slate-700 border-slate-200",_=e.url.split("?")[0];return y.jsx("div",{className:"py-16 border-t border-slate-200/60 group/row",id:e.name,children:y.jsxs("div",{className:"grid grid-cols-1 xl:grid-cols-12 gap-12 lg:gap-16",children:[y.jsxs("div",{className:"xl:col-span-5 space-y-8",children:[y.jsxs("div",{children:[y.jsxs("div",{className:"flex items-center gap-4 mb-4",children:[y.jsx("span",{className:`px-2.5 py-1 rounded text-xs font-bold tracking-widest border ${h}`,children:e.method}),y.jsx("h3",{className:"text-2xl font-bold text-slate-900 tracking-tight",children:e.name})]}),y.jsx("p",{className:"text-[15px] text-slate-600 leading-relaxed",children:e.description})]}),y.jsxs("div",{className:"bg-white border border-slate-200/80 rounded-xl p-3.5 font-mono text-sm shadow-sm flex items-start gap-2 group-hover/row:border-brand-300 transition-colors min-w-0",children:[y.jsx(ar,{size:14,className:"text-brand-400 shrink-0 mt-0.5"}),y.jsxs("div",{className:"min-w-0 flex-1",children:[y.jsx("div",{className:"text-xs text-slate-400 truncate",children:t.baseUrl}),y.jsx("div",{className:"font-semibold text-slate-800 break-all",children:_})]})]}),e.method==="GET"&&Object.keys(s).length>0&&y.jsxs("div",{className:"pt-2",children:[y.jsxs("h4",{className:"text-xs font-bold text-slate-400 mb-4 uppercase tracking-widest flex items-center gap-2",children:[y.jsx("span",{className:"w-4 h-[1px] bg-slate-300"})," Query Parameters"]}),y.jsx("div",{className:"space-y-4",children:Object.entries(s).map(([z,T])=>y.jsxs("div",{className:"flex flex-col gap-2",children:[y.jsxs("label",{className:"text-sm font-semibold text-slate-800 flex justify-between items-center",children:[z,y.jsx("span",{className:"text-[10px] text-slate-400 uppercase tracking-wider font-mono",children:"string"})]}),y.jsx("input",{className:"w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 transition-all shadow-sm text-slate-700",value:T,placeholder:`Enter ${z}...`,onChange:M=>{const A=M.target.value;if(f(N=>({...N,[z]:A})),!a)try{c(JSON.stringify({...JSON.parse(u||"{}"),[z]:isNaN(A)||A===""?A:Number(A)},null,2))}catch{}}})]},z))})]})]}),y.jsx("div",{className:"xl:col-span-7",children:y.jsxs("div",{className:"dark-glass rounded-2xl overflow-hidden shadow-code flex flex-col h-full min-h-[450px] transform transition-transform duration-500 group-hover/row:-translate-y-1",children:[y.jsxs("div",{className:"h-10 bg-white/5 border-b border-white/5 flex items-center px-4 gap-2 shrink-0",children:[y.jsx("div",{className:"w-3 h-3 rounded-full bg-red-500/80"}),y.jsx("div",{className:"w-3 h-3 rounded-full bg-amber-500/80"}),y.jsx("div",{className:"w-3 h-3 rounded-full bg-emerald-500/80"}),y.jsx("div",{className:"ml-4 text-xs font-mono text-slate-500",children:"Request Payload"})]}),l?y.jsxs("div",{className:"flex-1 grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-white/5",children:[y.jsxs("div",{className:"p-5 flex flex-col group/pane relative",children:[y.jsxs("div",{className:"text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider flex items-center gap-2",children:[y.jsx(er,{size:14,className:"text-brand-400"})," GraphQL Query"]}),y.jsx("textarea",{className:"flex-1 w-full bg-transparent text-slate-300 font-mono text-[13px] focus:outline-none resize-none leading-relaxed selection:bg-brand-500/30 scrollbar-hide",value:n,onChange:z=>i(z.target.value),spellCheck:"false"})]}),y.jsxs("div",{className:"p-5 flex flex-col bg-white/[0.02]",children:[y.jsx("div",{className:"text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider",children:"Variables JSON"}),y.jsx("textarea",{className:"flex-1 w-full bg-transparent text-emerald-400 font-mono text-[13px] focus:outline-none resize-none leading-relaxed selection:bg-emerald-500/30 scrollbar-hide",value:u,onChange:z=>c(z.target.value),spellCheck:"false"})]})]}):e.body?y.jsxs("div",{className:"flex-1 p-5 flex flex-col",children:[y.jsxs("div",{className:"text-[11px] font-bold text-slate-400 mb-3 uppercase tracking-wider flex items-center gap-2",children:[y.jsx(er,{size:14,className:"text-brand-400"})," Request Body (JSON)"]}),y.jsx("pre",{className:"flex-1 text-slate-300 font-mono text-[13px] whitespace-pre-wrap leading-relaxed overflow-auto scrollbar-hide",dangerouslySetInnerHTML:{__html:nr(e.body)}})]}):y.jsxs("div",{className:"flex-1 p-8 flex flex-col justify-start",children:[y.jsxs("div",{className:"text-[11px] font-bold text-slate-400 mb-4 uppercase tracking-wider flex items-center gap-2",children:[y.jsx(ar,{size:14,className:"text-brand-400"})," Full Request URL"]}),y.jsxs("div",{className:"font-mono text-[13px] leading-loose break-all",children:[y.jsx("span",{className:`font-bold mr-2 ${e.method==="GET"?"text-emerald-400":e.method==="POST"?"text-blue-400":e.method==="PUT"?"text-amber-400":e.method==="DELETE"?"text-red-400":"text-purple-400"}`,children:e.method}),y.jsx("span",{className:"text-slate-500",children:t.baseUrl}),y.jsx("span",{className:"text-slate-200",children:_}),Object.keys(s).length>0&&y.jsxs(y.Fragment,{children:[y.jsx("span",{className:"text-pink-400",children:"?"}),Object.entries(s).map(([z,T],M,A)=>y.jsxs("span",{children:[y.jsx("span",{className:"text-brand-300",children:z}),y.jsx("span",{className:"text-slate-500",children:"="}),y.jsx("span",{className:"text-slate-300",children:encodeURIComponent(T)}),My.jsx(vy,{endpoint:t,topic:e},`${e.uniqueId}/${t.name}`))})]}):null}const _m="https://fiesta.nearle.app",by=[{id:"utils",name:"Utils",description:"Shared lookup endpoints: app categories, subcategories, locations, app types, configs.",endpoints:[{name:"Fetch application categories by tag (Web)",method:"GET",url:"/live/api/v1/web/utils/getapptypes?tag=customer",description:"Fetch application categories by tag (Web)"},{name:"Resolve subcategories (Web)",method:"GET",url:"/live/api/v1/web/utils/getsubcategories?moduleid=1&categoryid=2",description:"Resolve subcategories (Web)"},{name:"Fetch system active geofence details (Web)",method:"GET",url:"/live/api/v1/web/utils/getapplocations?applocationid=1",description:"Fetch system active geofence details (Web)"},{name:"Fetch global system categories configurations (Web)",method:"GET",url:"/live/api/v1/web/utils/getappcategories",description:"Fetch global system categories configurations (Web)"},{name:"Get mobile geofence configuration details (Mobile)",method:"GET",url:"/live/api/v1/mob/utils/getapplocationconfig?applocationid=1",description:"Get mobile geofence configuration details (Mobile)"},{name:"Get mobile active geofence details (Mobile)",method:"GET",url:"/live/api/v1/mob/utils/getapplocations?applocationid=1",description:"Get mobile active geofence details (Mobile)"},{name:"Fetch mobile app types by tag (Mobile)",method:"GET",url:"/live/api/v1/mob/utils/getapptypes?tag=rider",description:"Fetch mobile app types by tag (Mobile)"},{name:"Fetch global payment & geofence configs (Mobile)",method:"GET",url:"/live/api/v1/mob/utils/getappconfig?configid=1",description:"Fetch global payment & geofence configs (Mobile)"},{name:"Get mobile category subcategories list (Mobile)",method:"GET",url:"/live/api/v1/mob/utils/getsubcategories?moduleid=1&categoryid=2",description:"Get mobile category subcategories list (Mobile)"},{name:"Fetch mobile app categories configurations (Mobile)",method:"GET",url:"/live/api/v1/mob/utils/getappcategories",description:"Fetch mobile app categories configurations (Mobile)"}]},{id:"users",name:"Users",description:"Manage users, authentication, and roles across the platform.",endpoints:[{name:"Get all users (Web)",method:"GET",url:"/live/api/v1/web/users/getallusers?roleid=2&tenantid=8&pageno=1&pagesize=10&keyword=john",description:"Get all users (Web)"},{name:"Get a specific user profile by ID (Web)",method:"GET",url:"/live/api/v1/web/users/getusers?userid=12",description:"Get a specific user profile by ID (Web)"},{name:"Get a specific user profile by ID (Mobile)",method:"GET",url:"/live/api/v1/mob/users/getusers?userid=15",description:"Get a specific user profile by ID (Mobile)"},{name:"Operator/User orders board (Web)",method:"GET",url:"/live/api/v1/web/orders/user/getorders?appuserid=12&status=processing&pageno=1&pagesize=10",description:"Operator/User orders board (Web)"},{name:"Tenant Web Panel Login",method:"POST",url:"/live/api/v1/web/users/tenant/weblogin",description:"Tenant Web Panel Login",body:{authname:"merchant_admin_01",password:"PasswordSecurityHash99!"}},{name:"General Application Login",method:"POST",url:"/live/api/v1/web/users/applogin",description:"General Application Login",body:{authname:"system_operator",password:"OperatorSafePasswordSecret",deviceid:"device_uuid_8828b",devicetype:"android"}},{name:"Register New Web Staff Account",method:"POST",url:"/live/api/v1/web/users/create",description:"Register New Web Staff Account",body:{authname:"tenant_staff_steve",firstname:"Steve",lastname:"Rogers",password:"SteveSecurePassword12",email:"steve.rogers@merchant.com",dialcode:"+61",contactno:"412345678",roleid:3,pin:1234,address:"100 Flinders St",suburb:"Melbourne",city:"Melbourne",state:"VIC",postcode:"3000",tenantid:8,locationid:2,applocationid:1,status:"active"}},{name:"Update Web Staff User Details",method:"PUT",url:"/live/api/v1/web/users/update",description:"Update Web Staff User Details",body:{userid:15,firstname:"Steve",lastname:"Captain",email:"steve.captain@merchant.com",contactno:"412345678",address:"200 Flinders St",suburb:"Melbourne",city:"Melbourne",state:"VIC",postcode:"3000",status:"active"}},{name:"Rider/Merchant Mobile App Login",method:"POST",url:"/live/api/v1/mob/users/tenant/login",description:"Rider/Merchant Mobile App Login",body:{authname:"rider_john_01",password:"RiderSecretKey"}},{name:"Create Mobile Staff User",method:"POST",url:"/live/api/v1/mob/users/create",description:"Create Mobile Staff User",body:{authname:"tenant_staff_steve",firstname:"Steve",lastname:"Rogers",password:"SteveSecurePassword12",email:"steve.rogers@merchant.com",dialcode:"+61",contactno:"412345678",roleid:3,pin:1234,tenantid:8,locationid:2,applocationid:1,status:"active"}},{name:"Update Mobile Staff Details",method:"PUT",url:"/live/api/v1/mob/users/update",description:"Update Mobile Staff Details",body:{userid:15,firstname:"Steve",lastname:"Captain",email:"steve.captain@merchant.com",contactno:"412345678",status:"active"}}]},{id:"partners",name:"Partners",description:"Partners, riders, shifts, locations, and log sheets.",endpoints:[{name:"Partner fleet orders board (Web)",method:"GET",url:"/live/api/v1/web/orders/partner/getorders?partnerid=1&status=processing&pageno=1&pagesize=10",description:"Partner fleet orders board (Web)"},{name:"Get active riders (Web)",method:"GET",url:"/live/api/v1/web/partners/getriders?partnerid=1&applocationid=1&userid=12&tenantid=8",description:"Get active riders (Web)"},{name:"Get partner profiles (Web)",method:"GET",url:"/live/api/v1/web/partners/getpartners?partnerid=1&applocationid=1&userid=12",description:"Get partner profiles (Web)"},{name:"Get rider shifts (Web)",method:"GET",url:"/live/api/v1/web/partners/getridershifts?applocationid=1",description:"Get rider shifts (Web)"},{name:"Get location configurations (Web)",method:"GET",url:"/live/api/v1/web/partners/getlocations?userid=12&configid=1",description:"Get location configurations (Web)"},{name:"Get rider log sheet (Web)",method:"GET",url:"/live/api/v1/web/partners/getriderlogs?partnerid=1&applocationid=1&fromdate=2026-05-20&todate=2026-05-20",description:"Get rider log sheet (Web)"},{name:"Get partner profiles (Mobile)",method:"GET",url:"/live/api/v1/mob/partners/getpartners?partnerid=1&applocationid=1&userid=12",description:"Get partner profiles (Mobile)"},{name:"Get rider log sheet (Mobile)",method:"GET",url:"/live/api/v1/mob/partners/getriderlogs?partnerid=1&applocationid=1&fromdate=2026-05-20&todate=2026-05-20",description:"Get rider log sheet (Mobile)"},{name:"Get rider operational info (Mobile)",method:"GET",url:"/live/api/v1/mob/partners/getriderinfo?userid=15",description:"Get rider operational info (Mobile)"},{name:"Get active riders list (Mobile)",method:"GET",url:"/live/api/v1/mob/partners/getriders?partnerid=1&applocationid=1&userid=15&tenantid=8",description:"Get active riders list (Mobile)"}]},{id:"tenants",name:"Tenants",description:"Tenant accounts, locations, customers, pricing, onboarding.",endpoints:[{name:"Tenant orders board (Web)",method:"GET",url:"/live/api/v1/web/orders/tenant/getorders?tenantid=8&locationid=2&status=processing&pageno=1&pagesize=10",description:"Tenant orders board (Web)"},{name:"Get specific tenant store orders (Mobile)",method:"GET",url:"/live/api/v1/mob/orders/tenant/getorders?tenantid=8&locationid=2&pageno=1&pagesize=10",description:"Get specific tenant store orders (Mobile)"},{name:"Search registered tenants (Web)",method:"GET",url:"/live/api/v1/web/tenants/search?status=Active&keyword=Fresh",description:"Search registered tenants (Web)"},{name:"Search tenants by keyword (Web)",method:"GET",url:"/live/api/v1/web/tenants/searchbykeyword?keyword=daily",description:"Search tenants by keyword (Web)"},{name:"Get all active tenants catalog (Web)",method:"GET",url:"/live/api/v1/web/tenants/getalltenants?applocationid=1&status=Active&pageno=1&pagesize=10",description:"Get all active tenants catalog (Web)"},{name:"Get outlet locations assigned to a tenant (Web)",method:"GET",url:"/live/api/v1/web/tenants/gettenantlocations?tenantid=8",description:"Get outlet locations assigned to a tenant (Web)"},{name:"Retrieve delivery time slots config (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/gettenantslot",description:"Retrieve delivery time slots config (Mobile)"},{name:"Search tenants by keyword (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/searchbykeyword?keyword=grocery",description:"Search tenants by keyword (Mobile)"},{name:"Retrieve tenants associated with a customer (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/getcustomertenants?customerid=4082&tenant=0",description:"Retrieve tenants associated with a customer (Mobile)"},{name:"Get outlet locations linked to a tenant (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/gettenantlocations?tenantid=8",description:"Get outlet locations linked to a tenant (Mobile)"},{name:"Get logistics pricing slabs for a tenant (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/gettenantpricing?tenantid=8&applocationid=1",description:"Get logistics pricing slabs for a tenant (Mobile)"},{name:"Get staff members under a tenant store (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/getstaffs?tenantid=8",description:"Get staff members under a tenant store (Mobile)"},{name:"Get tenant detailed profile info (Mobile)",method:"GET",url:"/live/api/v1/mob/tenants/gettenantinfo?tenantid=8&locationid=2",description:"Get tenant detailed profile info (Mobile)"},{name:"Link Customer Profile to Tenant Store",method:"POST",url:"/live/api/v1/web/tenants/createtenantcustomer",description:"Link Customer Profile to Tenant Store",body:{moduleid:1,tenantid:8,locationid:2,customerid:4082,customerlocationid:554,status:1}},{name:"Create New Geofenced Store Location",method:"POST",url:"/live/api/v1/web/tenants/createlocation",description:"Create New Geofenced Store Location",body:{tenantid:8,applocationid:1,moduleid:1,locationname:"Hawthorn Daily Fresh Store",email:"hawthorn.store@merchant.com",contactno:"399443322",latitude:"-37.8222",longitude:"145.0384",address:"12 Glenferrie Rd",suburb:"Hawthorn",city:"Melbourne",state:"VIC",postcode:"3122",opentime:"07:00:00",closetime:"22:00:00",partnerid:1,deliveryradius:5e3,deliverymins:30,cancelsecs:60,status:"Active"}},{name:"Update Store Location Configurations",method:"PUT",url:"/live/api/v1/web/tenants/updatelocation",description:"Update Store Location Configurations",body:{locationid:2,tenantid:8,applocationid:1,locationname:"Richmond Daily Fresh Store",email:"richmond.store@merchant.com",contactno:"399887766",latitude:"-37.8212",longitude:"144.9984",address:"Shop 4, 100 Church St",suburb:"Richmond",city:"Melbourne",state:"VIC",postcode:"3121",opentime:"07:00:00",closetime:"22:00:00",deliveryradius:8e3,deliverymins:45,cancelsecs:120,status:"Active"}},{name:"Onboard New Tenant & Admin Profile",method:"POST",url:"/live/api/v1/mob/tenants/createtenantuser",description:"Onboard New Tenant & Admin Profile (Joint Creation)",body:{tenantname:"Fresh Organic Greens",configid:1,partnerid:1,moduleid:1,tenanttype:"Enterprise",firstname:"Arthur",primaryemail:"arthur@organicgreens.com",primarycontact:"488999000",categoryid:2,subcategoryid:12,address:"400 Chapel St",suburb:"South Yarra",city:"Melbourne",state:"VIC",postcode:"3141",applocationid:1,approved:1,status:"Active"}}]},{id:"customers",name:"Customers",description:"Customer accounts, addresses, support requests, and search.",endpoints:[{name:"Fetch customer profile by ID or Contact (Mobile)",method:"GET",url:"/live/api/v1/mob/customers/getbyid?customerid=4082&contactno=9876543210",description:"Fetch customer profile by ID or Contact (Mobile)"},{name:"Get customer saved address locations (Mobile)",method:"GET",url:"/live/api/v1/mob/customers/getcustomerlocation?customerid=4082",description:"Get customer saved address locations (Mobile)"},{name:"Get customer logged support requests (Mobile)",method:"GET",url:"/live/api/v1/mob/customers/getcustomerrequests?customerid=4082&pageno=1&pagesize=10",description:"Get customer logged support requests (Mobile)"},{name:"Search customer names under a tenant (Mobile)",method:"GET",url:"/live/api/v1/mob/customers/search?keyword=Jane&tenantid=8",description:"Search customer names under a tenant (Mobile)"},{name:"Retrieve customers linked to a tenant location (Mobile)",method:"GET",url:"/live/api/v1/mob/customers/gettenantcustomers?tenantid=8&locationid=2&pageno=1&pagesize=10",description:"Retrieve customers linked to a tenant location (Mobile)"},{name:"Retrieve merchant customers list (Web)",method:"GET",url:"/live/api/v1/web/customers/gettenantcustomers?tenantid=8&locationid=2&pageno=1&pagesize=10&keyword=jane",description:"Retrieve merchant customers list (Web)"},{name:"Individual consumer invoice histories (Web)",method:"GET",url:"/live/api/v1/web/orders/customer/getorders?customerid=4082&status=delivered&pageno=1&pagesize=10",description:"Individual consumer invoice histories (Web)"},{name:"Passwordless OTP Login (via Phone)",method:"POST",url:"/live/api/v1/mob/customers/login",description:"Passwordless OTP Login (via Phone)",body:{contactno:"0499888777"}},{name:"Register Customer Account",method:"POST",url:"/live/api/v1/mob/customers/create",description:"Register Customer Account",body:{firstname:"Jane",lastname:"Smith",gender:"Female",dob:"1994-11-20",dialcode:"+61",contactno:"499888777",email:"jane.smith@gmail.com",deviceid:"uuid_7728b991a",devicetype:"ios",authmode:1,address:"456 Oak Avenue",suburb:"Richmond",city:"Melbourne",state:"VIC",postcode:"3121",latitude:"-37.8212",longitude:"144.9984",applocationid:1,status:1}},{name:"Save New Geofenced Location Address",method:"POST",url:"/live/api/v1/mob/customers/createlocations",description:"Save New Geofenced Location Address",body:{customerid:4082,address:"123 High Street",suburb:"Prahran",city:"Melbourne",state:"VIC",postcode:"3181",latitude:"-37.8502",longitude:"144.9924",primaryaddress:1,status:1}},{name:"Log Customer Support Ticket Request",method:"POST",url:"/live/api/v1/mob/customers/createcustomerrequest",description:"Log Customer Support Ticket Request",body:{customerid:4082,tenantid:8,apptypeid:1,locationid:2,subject:"Delay in Morning Milk Delivery",remarks:"Order scheduled for 7:00 AM hasn't arrived.",status:1}},{name:"Update Customer Profile Details",method:"PUT",url:"/live/api/v1/mob/customers/update",description:"Update Customer Profile Details",body:{customerid:4082,firstname:"Jane",lastname:"Miller",email:"jane.miller@gmail.com",contactno:"499888777",status:1}}]},{id:"deliveries",name:"Deliveries",description:"Delivery dispatch, queues, summaries, and rider status tracking.",endpoints:[{name:"Get deliveries performance summaries (Web)",method:"GET",url:"/live/api/v1/web/deliveries/deliverysummary?tenantid=8&partnerid=1&userid=12&applocationid=1&locationid=2&fromdate=2026-05-20&todate=2026-05-20",description:"Get deliveries performance summaries (Web)"},{name:"Get daily delivery insights (Web)",method:"GET",url:"/live/api/v1/web/deliveries/getdeliveryinsight?tenantid=8",description:"Get daily delivery insights (Web)"},{name:"Get location deliveries summary (Web)",method:"GET",url:"/live/api/v1/web/deliveries/getlocationsummary?tenantid=8",description:"Get location deliveries summary (Web)"},{name:"Get deliveries financial report summary (Web)",method:"GET",url:"/live/api/v1/web/deliveries/getreportsummary?tenantid=8&partnerid=1&userid=12&applocationid=1&fromdate=2026-05-01&todate=2026-05-20",description:"Get deliveries financial report summary (Web)"},{name:"Get fleet rider summary metrics (Web)",method:"GET",url:"/live/api/v1/web/deliveries/getridersummary?applocationid=1&partnerid=1&tenantid=8&fromdate=2026-05-20&todate=2026-05-20",description:"Get fleet rider summary metrics (Web)"},{name:"Get master deliveries board (Web)",method:"GET",url:"/live/api/v1/web/deliveries/getdeliveries?tenantid=8&fromdate=2026-05-20&todate=2026-05-20",description:"Get master deliveries board (Web)"},{name:"Get mobile dispatch summaries (Mobile)",method:"GET",url:"/live/api/v1/mob/deliveries/deliverysummary?userid=15&fromdate=2026-05-20&todate=2026-05-20",description:"Get mobile dispatch summaries (Mobile)"},{name:"Get mobile deliveries board (Mobile)",method:"GET",url:"/live/api/v1/mob/deliveries/getdeliveries?userid=15&status=assigned",description:"Get mobile deliveries board (Mobile)"},{name:"Fetch rider active shift deliveries queue (Mobile)",method:"GET",url:"/live/api/v1/mob/deliveries/getdeliveryqueues?userid=15&fromdate=2026-05-20&todate=2026-05-20",description:"Fetch rider active shift deliveries queue (Mobile)"},{name:"Initialize Logistics Delivery Dispatch (Assign Rider)",method:"POST",url:"/live/api/v1/web/deliveries/createdeliveries",description:"Initialize Logistics Delivery Dispatch",body:[{orderheaderid:2100,applocationid:1,partnerid:1,tenantid:8,moduleid:1,locationid:2,userid:15,orderid:"ORD-19028-4",deliverydate:"2026-05-20",orderstatus:"assigned",assigntime:"2026-05-20 12:10:00",itemcount:2,orderamount:12.58,customerid:4082,pickupcustomer:"Central Merchant Warehouse",pickupcontactno:"987654321",pickuplocationid:2,pickupaddress:"Shop 4, Central Plaza, Melbourne",pickuplat:"-37.8136",pickuplon:"144.9631",deliverycustomerid:4082,deliverylocationid:554,deliverycustomer:"Jane Smith",deliverycontactno:"499888777",deliveryaddress:"456 Oak Avenue, Richmond, VIC, 3121",droplat:"-37.8212",droplon:"144.9984",deliverycharges:3,deliveryamt:15.58,deliverytype:"standard",paymenttype:1}]},{name:"Update Rider Pickup Status",method:"PUT",url:"/live/api/v1/web/deliveries/updatedelivery",description:"Update Rider Pickup Status",body:{deliveryid:8871,orderheaderid:2100,userid:15,orderstatus:"picked",pickuptime:"2026-05-20 12:20:00",riderslat:"-37.8140",riderslon:"144.9640"}},{name:"Rider Update Dispatch Status (Delivered)",method:"PUT",url:"/live/api/v1/mob/deliveries/updatedelivery",description:"Rider Update Dispatch Status (Delivered & GPS Tracking)",body:{deliveryid:8871,orderheaderid:2100,userid:15,orderstatus:"delivered",deliverytime:"2026-05-20 12:45:00",riderslat:"-37.8210",riderslon:"144.9980",actualkms:"4.2",feedback:"Handed over safely.",smsdelivery:1}}]},{id:"orders",name:"Orders",description:"Order boards, details, summaries, and status management.",endpoints:[{name:"Filtered dynamic orders board (Web)",method:"GET",url:"/live/api/v1/web/orders/getorders?tenantid=8&locationid=2&status=processing&pageno=1&pagesize=10",description:"Filtered dynamic orders board (Web)"},{name:"System Admin orders board (Web)",method:"GET",url:"/live/api/v1/web/orders/admin/getorders?applocationid=1&status=processing&pageno=1&pagesize=10",description:"System Admin orders board (Web)"},{name:"Get order dashboard stats summary (Web)",method:"GET",url:"/live/api/v1/web/orders/getordersummary?tenantid=8&fromdate=2026-05-01&todate=2026-05-20",description:"Get order dashboard stats summary (Web)"},{name:"Get location orders summary (Web)",method:"GET",url:"/live/api/v1/web/orders/getlocationsummary?tenantid=8",description:"Get location orders summary (Web)"},{name:"Get annual orders insights analytics (Web)",method:"GET",url:"/live/api/v1/web/orders/getorderinsight?tenantid=8",description:"Get annual orders insights analytics (Web)"},{name:"Get order detailed lines (Web)",method:"GET",url:"/live/api/v1/web/orders/getorderdetails?orderheaderid=2099",description:"Get order detailed lines (Web)"},{name:"Get customer order history (Mobile)",method:"GET",url:"/live/api/v1/mob/orders/getcustomerorders?customerid=4082&pageno=1&pagesize=10",description:"Get customer order history (Mobile)"},{name:"Get mobile order detailed lines (Mobile)",method:"GET",url:"/live/api/v1/mob/orders/getorderdetails?orderheaderid=2099",description:"Get mobile order detailed lines (Mobile)"},{name:"Create New Web Order",method:"POST",url:"/live/api/v1/web/orders/createorder",description:"Create New Web Order (Flat JSON Format)",body:{tenantid:8,locationid:2,applocationid:1,moduleid:1,customerid:4082,orderstatus:"pending",deliverytype:"standard",deliverytime:"2026-05-20 18:00:00",pickupaddress:"Shop 4, Central Plaza, Melbourne",pickuplat:"-37.8136",pickuplong:"144.9631",pickupcustomer:"Central Plaza Merchant",pickupcontactno:"399887766",deliveryaddress:"Apt 4B, Sunset Boulevard, Richmond",deliverylat:"-37.8212",deliverylong:"144.9984",orderamount:11.48,taxamount:1.1,ordervalue:12.58,itemcount:2,paymenttype:1,paymentstatus:0,deliverycharge:3,items:[{productid:105,productname:"Organic Whole Milk 1L",orderqty:2,price:3.99,taxpercentage:10,taxamount:.8,productsumprice:7.98}]}},{name:"Update Order Status & Financial Flag",method:"PUT",url:"/live/api/v1/web/orders/updateorder",description:"Update Order Status & Financial Flag",body:{orderheaderid:2099,orderstatus:"ready",paymentstatus:1,remarks:"Order packed and waiting for rider assignment."}},{name:"Create Mobile Order",method:"POST",url:"/live/api/v1/mob/orders/createorder",description:"Create Mobile Order (Wrapped JSON Format)",body:{orders:{tenantid:8,locationid:2,applocationid:1,moduleid:1,customerid:4082,orderstatus:"pending",deliverytype:"standard",deliverytime:"2026-05-20 18:00:00",pickupaddress:"Shop 4, Central Plaza, Melbourne",orderamount:11.48,taxamount:1.1,ordervalue:12.58,itemcount:2,paymenttype:1,paymentstatus:0,deliverycharge:3,items:[{productid:105,productname:"Organic Whole Milk 1L",orderqty:2,price:3.99,taxpercentage:10,taxamount:.8,productsumprice:7.98}]}}},{name:"Mobile Update Order Status",method:"PUT",url:"/live/api/v1/mob/orders/updateorder",description:"Mobile Update Order Status",body:{orderheaderid:2099,orderstatus:"ready",paymentstatus:1,remarks:"Order packed and waiting for rider assignment."}}]},{id:"products",name:"Products",description:"Product catalog, stock management, variants, and outlet inventory.",endpoints:[{name:"Get product subcategories (Web)",method:"GET",url:"/live/api/v1/web/products/getproductsubcategories?categoryid=2&tenantid=8",description:"Get product subcategories (Web)"},{name:"Get products stock counts (Web)",method:"GET",url:"/live/api/v1/web/products/getproductscount?tenantid=8&categoryid=2&subcategoryid=12&approve=1",description:"Get products stock counts (Web)"},{name:"Get all global categories (Web)",method:"GET",url:"/live/api/v1/web/products/getproductcategories",description:"Get all global categories (Web)"},{name:"Get specific product variants (Web)",method:"GET",url:"/live/api/v1/web/products/getproductvariants?tenantid=8&subcategoryid=12",description:"Get specific product variants (Web)"},{name:"Get master catalog listings (Web)",method:"GET",url:"/live/api/v1/web/products/getcatalougeproducts?tenantid=8&locationid=2&subcategoryid=12&keyword=&pageno=1&pagesize=10",description:"Get master catalog listings (Web)"},{name:"Get live stocks catalog (Web)",method:"GET",url:"/live/api/v1/web/products/getproductstocks?tenantid=8&locationid=2",description:"Get live stocks catalog (Web)"},{name:"Get dynamic stock statement ledger (Web)",method:"GET",url:"/live/api/v1/web/products/getstockstatement?tenantid=8&locationid=2&subcategoryid=12&pageno=1&pagesize=10&keyword=",description:"Get dynamic stock statement ledger (Web)"},{name:"Get outlet geofenced inventory (Web)",method:"GET",url:"/live/api/v1/web/products/getlocationproducts?tenantid=8&locationid=2&subcategoryid=12&pageno=1&pagesize=10",description:"Get outlet geofenced inventory (Web)"},{name:"Master products search board (Web)",method:"GET",url:"/live/api/v1/web/products/getallproducts?tenantid=8&locationid=2&keyword=milk&pageno=1&pagesize=10",description:"Master products search board (Web)"},{name:"Get product details by variant ID (Mobile)",method:"GET",url:"/live/api/v1/mob/products/getproductbyvariant?tenantid=8&variantid=4",description:"Get product details by variant ID (Mobile)"},{name:"Get product subcategories (Mobile)",method:"GET",url:"/live/api/v1/mob/products/getproductsubcategories?categoryid=2&tenantid=8",description:"Get product subcategories (Mobile)"},{name:"Search product catalog (Mobile)",method:"GET",url:"/live/api/v1/mob/products/getallproducts?keyword=milk&pageno=1&pagesize=10",description:"Search product catalog (Mobile)"},{name:"Get mobile geofenced outlet products (Mobile)",method:"GET",url:"/live/api/v1/mob/products/getlocationproducts?tenantid=8&locationid=2&pageno=1&pagesize=20",description:"Get mobile geofenced outlet products (Mobile)"},{name:"Add Multi-Product Stock Entry",method:"POST",url:"/live/api/v1/web/products/createproductstock",description:"Add Multi-Product Stock Entry",body:[{tenantid:8,locationid:2,productid:105,quantity:150,stocktype:"credit",status:"active"},{tenantid:8,locationid:2,productid:109,quantity:80,stocktype:"credit",status:"active"}]},{name:"Create Master Product Catalog Item",method:"POST",url:"/live/api/v1/web/products/create",description:"Create Master Product Catalog Item",body:{applocationid:1,tenantid:8,categoryid:2,subcategoryid:12,productname:"Fresh Cow Milk 1L",productunit:"Litre",unitvalue:"1",productcost:1.8,retailprice:3.5,taxpercent:5,productstock:100,productstatus:"available",approve:1}},{name:"Update Master Product Details",method:"PUT",url:"/live/api/v1/web/products/update",description:"Update Master Product Details",body:{productid:105,productname:"Organic Farm Cow Milk 1L",productcost:1.95,retailprice:3.75,productstock:120,productstatus:"available"}},{name:"Purge Master Product Catalog Entry",method:"DELETE",url:"/live/api/v1/web/products/delete?productid=105",description:"Purge Master Product Catalog Entry"}]},{id:"invoice",name:"Invoice",description:"Invoice insights and billing analytics.",endpoints:[{name:"Get invoice insights for a tenant",method:"GET",url:"/live/api/v1/web/invoice/getinvoiceinsight?tenantid=8",description:"Retrieve invoice insights and statistics for a tenant."}]},{id:"payments",name:"Payments",description:"Payment requests and settlement records.",endpoints:[{name:"Get payment requests for a partner",method:"GET",url:"/live/api/v1/web/payments/requests/getpaymentrequest?partnerid=44&status=1",description:"List payment requests for a partner by status."}]}],Sy={users:Tm,orders:bm,tenants:vm,products:bi,locations:hm,partners:mm,deliveries:Sm,customers:pm,invoice:gm,payments:ym,utils:xm,mobile:bi};function Ty({allGraphql:e,allRest:t,setActiveTopic:a}){const l=[...e,...t];return y.jsxs("div",{className:"max-w-[1000px] mx-auto px-12 py-20 lg:px-24 lg:py-28",children:[y.jsxs("div",{className:"inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-50 border border-brand-100 text-brand-600 text-sm font-medium mb-8",children:[y.jsx(lr,{size:14,className:"fill-current"}),"v2.0 Developer API"]}),y.jsx("h1",{className:"text-4xl lg:text-5xl font-bold text-slate-900 mb-6 tracking-tight",children:y.jsx("span",{className:"text-gradient",children:"NearleDaily API"})}),y.jsx("p",{className:"text-xl text-slate-600 mb-12 max-w-2xl leading-relaxed",children:"A comprehensive, lightning-fast platform designed for logistics, order management, and multi-tenant POS administration β€” available through both Hasura GraphQL and REST APIs."}),y.jsxs("div",{className:"mb-8",children:[y.jsx("h2",{className:"text-xs font-bold uppercase tracking-widest text-slate-400 mb-4",children:"Base URLs"}),y.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3 mb-10",children:[y.jsxs("div",{className:"bg-white border border-slate-200/60 rounded-xl p-4 shadow-sm",children:[y.jsx("div",{className:"text-[11px] text-brand-600 font-bold uppercase tracking-widest mb-1.5",children:"GraphQL"}),y.jsx("code",{className:"font-mono text-sm text-slate-700",children:Em})]}),y.jsxs("div",{className:"bg-white border border-slate-200/60 rounded-xl p-4 shadow-sm",children:[y.jsx("div",{className:"text-[11px] text-indigo-600 font-bold uppercase tracking-widest mb-1.5",children:"REST API"}),y.jsx("code",{className:"font-mono text-sm text-slate-700",children:_m})]})]})]}),y.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:l.map((n,i)=>{const u=Sy[n.id]||lr;return y.jsxs("div",{onClick:()=>a(n),className:"group relative bg-white p-6 rounded-2xl border border-slate-200/60 shadow-sm hover:shadow-xl hover:shadow-brand-500/5 hover:border-brand-200 transition-all duration-300 cursor-pointer overflow-hidden",style:{animationDelay:`${i*80}ms`},children:[y.jsx("div",{className:"absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-brand-50 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500"}),y.jsxs("div",{className:"relative z-10",children:[y.jsxs("h3",{className:"text-lg font-bold text-slate-900 mb-2 group-hover:text-brand-600 transition-colors flex items-center gap-2",children:[y.jsx("div",{className:"p-1.5 bg-brand-50 text-brand-600 rounded-md group-hover:bg-brand-100 transition-colors",children:y.jsx(u,{size:18})}),n.name,y.jsx(Op,{size:16,className:"opacity-0 -translate-x-4 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 ml-auto"})]}),y.jsxs("div",{className:"flex items-center gap-2 mt-1 mb-2",children:[y.jsx("span",{className:`text-[10px] font-bold uppercase tracking-widest px-2 py-0.5 rounded border ${n.type==="graphql"?"bg-brand-50 text-brand-600 border-brand-100":"bg-indigo-50 text-indigo-600 border-indigo-100"}`,children:n.type==="graphql"?"GraphQL":"REST"}),y.jsxs("span",{className:"text-[11px] text-slate-400",children:[n.endpoints.length," endpoint",n.endpoints.length!==1?"s":""]})]}),y.jsx("p",{className:"text-sm text-slate-500 leading-relaxed",children:n.description})]})]},n.uniqueId)})}),y.jsxs("div",{className:"mt-16 flex items-center gap-4 p-6 bg-slate-900 text-slate-300 rounded-2xl shadow-code",children:[y.jsx(Xp,{className:"text-brand-400 shrink-0",size:24}),y.jsx("p",{className:"text-sm",children:"Explore real-time interactive endpoints. GraphQL requests are authenticated with the admin secret. REST endpoints support CORS and can be called directly from the browser."})]})]})}const zm=(e,t,a)=>e.map(l=>({...l,baseUrl:t,type:a,uniqueId:`${a}-${l.id}`})),ur=zm(my,Em,"graphql"),cr=zm(by,_m,"rest");function sr(e,t){return t?e.filter(a=>a.name.toLowerCase().includes(t)||(a.description||"").toLowerCase().includes(t)||a.endpoints.some(l=>l.name.toLowerCase().includes(t)||l.url.toLowerCase().includes(t)||(l.description||"").toLowerCase().includes(t))):e}function xy(){const[e,t]=P.useState(null),[a,l]=P.useState(""),n=a.trim().toLowerCase(),i=P.useMemo(()=>sr(ur,n),[n]),u=P.useMemo(()=>sr(cr,n),[n]);return y.jsxs("div",{className:"min-h-screen bg-slate-50 bg-grid-pattern flex relative overflow-hidden",children:[y.jsx("div",{className:"absolute top-0 -left-4 w-72 h-72 bg-brand-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob"}),y.jsx("div",{className:"absolute top-0 -right-4 w-72 h-72 bg-indigo-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob animation-delay-2000"}),y.jsx("div",{className:"absolute -bottom-8 left-20 w-72 h-72 bg-pink-300 rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-blob animation-delay-4000"}),y.jsx(fy,{graphqlTopics:i,restTopics:u,activeTopic:e,setActiveTopic:t,searchQuery:a,setSearchQuery:l}),y.jsx("main",{className:"ml-[280px] flex-1 min-h-screen relative z-10",children:e?y.jsx("div",{className:"max-w-[1200px] mx-auto p-12 lg:p-16 opacity-0 animate-fade-in-up",children:y.jsx(hy,{topic:e})}):y.jsx("div",{className:"opacity-0 animate-fade-in-up",children:y.jsx(Ty,{allGraphql:ur,allRest:cr,setActiveTopic:t})})})]})}xp.createRoot(document.getElementById("root")).render(y.jsx(P.StrictMode,{children:y.jsx(xy,{})})); diff --git a/src/App.tsx b/src/App.tsx index 8621b94..4fd963c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,6 @@ import { Truck, Sliders, Calendar, - AlertTriangle, FileCheck, Building, CheckCircle2, @@ -42,9 +41,54 @@ import ReportsView from './components/ReportsView'; import InventoryView from './components/InventoryView'; import SettingsView from './components/SettingsView'; import StoreDetailView from './components/StoreDetailView'; +import LoginView from './components/LoginView'; +import UserStorePage from './components/UserStorePage'; +import AwaitingApi from './components/AwaitingApi'; +import type { AuthUser } from './services/auth'; import ragulStoreCover from './assets/images/store_front_view_1780299351800.png'; +const AUTH_STORAGE_KEY = 'nearledaily.auth'; + +/** Rehydrate the signed-in user from localStorage (keeps the session across refreshes). */ +function loadStoredUser(): AuthUser | null { + try { + const raw = localStorage.getItem(AUTH_STORAGE_KEY); + if (!raw) return null; + const parsed = JSON.parse(raw) as AuthUser; + return parsed && typeof parsed === 'object' && (parsed.role === 'admin' || parsed.role === 'user') + ? parsed + : null; + } catch { + return null; + } +} + export default function App() { + // Auth gate β€” null = signed out (show login). Admin β†’ full dashboard, user β†’ + // their single store console. The verified user is persisted to localStorage so + // a refresh keeps the session (rehydrated via the lazy initializer); authRole + // is derived from it so the two can't drift out of sync. + const [authUser, setAuthUser] = useState(() => loadStoredUser()); + const authRole = authUser?.role ?? null; + + // Persist (or clear) the session whenever the signed-in user changes. + useEffect(() => { + try { + if (authUser) localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(authUser)); + else localStorage.removeItem(AUTH_STORAGE_KEY); + } catch { + /* storage unavailable (private mode / quota) β€” session just won't persist */ + } + }, [authUser]); + + const handleLogin = (user: AuthUser) => setAuthUser(user); + + const currentUser = { + name: authUser?.name || 'Account', + role: authRole === 'admin' ? 'Operations Admin' : 'Team Member', + email: authUser?.email || 'β€”', + }; + // Navigation indicators states const [currentSection, setCurrentSection] = useState('dashboard'); const [selectedStore, setSelectedStore] = useState<{ locationid?: number; name: string; zone: string; deliveries: number; sales: string; orders?: number; staff: string; color: string; status: string } | null>(null); @@ -176,35 +220,53 @@ export default function App() { const [showCalendarModal, setShowCalendarModal] = useState(false); // Callback action triggers - const handleNewReport = () => { - setCurrentSection('reports'); - alert('System routed back to reports dashboard interface. Select product item metadata matrices.'); - }; - const handleHelp = () => { alert('nearledaily User Manual & Documentation Center linked successfully. Contact Coimbatore regional IT hub desk for urgent escalations.'); }; - const handleLogout = () => { - const ok = window.confirm('Are you sure you want to terminate this active secure session?'); - if (ok) { - alert('Secure session suspended. Page reloading and restarting database state simulation.'); - window.location.reload(); - } - }; + const handleLogout = () => setAuthUser(null); // Define secondary sections (Stores, Logistics, Staffing, Settings) within main body const renderSecondarySection = () => { switch (currentSection) { - case 'stores': - if (selectedStore) { + case 'stores': { + // A single-store merchant has no branches, so skip the one-card registry + // and open that store directly. Add a branch (2+ stores) and the grid + // returns automatically. Clicking a card in multi-store mode also opens + // the console, with a Back-to-registry button. + const isSoleStore = !selectedStore && storesList.length === 1; + const activeStore = selectedStore ?? (isSoleStore ? storesList[0] : null); + + if (activeStore) { return ( - setSelectedStore(null)} - /> +

+ {isSoleStore && ( +
+
+

+ Store Console +

+

+ This merchant operates a single store. Add a branch to manage multiple outlets. +

+
+ +
+ )} + setSelectedStore(null) : undefined} + /> +
); } + return (
{/* Simple and elegant premium header */} @@ -468,6 +530,7 @@ export default function App() {
); + } case 'settings': return ; @@ -477,6 +540,17 @@ export default function App() { } }; + // ── Auth gate ────────────────────────────────────────────────────────────── + // Signed out β†’ login screen. User role β†’ their single allocated store console + // (scoped by applocationid). Only the admin role reaches the full operations + // dashboard with the all-stores registry below. + if (authRole === null) { + return ; + } + if (authRole === 'user' && authUser) { + return ; + } + return (
{/* Navbar segment */} @@ -486,9 +560,9 @@ export default function App() { isCoimbatoreView={isCoimbatoreView} onToggleSidebar={() => setSidebarOpen((prev) => !prev)} isSidebarOpen={sidebarOpen} - onNewReportClick={handleNewReport} onHelpClick={handleHelp} onLogoutClick={handleLogout} + profile={currentUser} /> {/* Main Container workspace layout splits */} @@ -556,28 +630,10 @@ export default function App() {

- Automated compliance summaries are scheduled to generate and export on the following dates: + Automated compliance summaries will appear here once scheduled-report exports are available.

-
-
- Monthly Assortment Audit Ledger - Oct 31, 2023 -
-
- Daily Regional Turnover Sheet - Everyday 23:59 (GMT) -
-
- Q4 Outlook Forecast Draft - Nov 15, 2023 -
-
- -
- - Next automated sync will occur at standard local closing hour thresholds. -
+
diff --git a/src/components/AwaitingApi.tsx b/src/components/AwaitingApi.tsx new file mode 100644 index 0000000..f418b13 --- /dev/null +++ b/src/components/AwaitingApi.tsx @@ -0,0 +1,40 @@ +/** + * @license + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { PlugZap } from 'lucide-react'; + +/** + * Explicit "this data has no backend yet" placeholder. Used for UI sections whose + * live API is not built (see docs/03_REQUIRED_BACKEND_APIS.md β†’ [R*] ids). We show + * this instead of fabricated numbers so nothing fake reaches staging. + */ +export default function AwaitingApi({ + label, + api, + className = '', + compact = false, +}: { + /** What the section will show once wired (e.g. "Operational alerts"). */ + label: string; + /** The required-API id from the spec doc, e.g. "[R12]". */ + api?: string; + className?: string; + compact?: boolean; +}) { + return ( +
+ +

{label}

+

+ Awaiting backend API{api ? ` ${api}` : ''} β€” no live data source yet. +

+
+ ); +} diff --git a/src/components/DashboardView.tsx b/src/components/DashboardView.tsx index 3619fd7..b0ef479 100644 --- a/src/components/DashboardView.tsx +++ b/src/components/DashboardView.tsx @@ -5,15 +5,15 @@ import React from 'react'; import { - ShoppingBag, - PackageCheck, Wallet, TrendingUp, Store, MapPin, Phone, - Sparkles, AlertTriangle, + Activity, + Clock, + ArrowUpRight, } from 'lucide-react'; import { useOrderSummary, useTenantInfo, useTenantLocations, useInvoiceInsight } from '../services/queries'; import { DEFAULT_TENANT_ID, DEFAULT_CONFIG_ID } from '../services/api'; @@ -81,10 +81,42 @@ export default function DashboardView({ searchQuery }: DashboardViewProps) { const dashOffset = circumference - (circumference * activePct) / 100; const kpis = [ - { title: 'ACTIVE OUTLETS', display: `${activeStoresCount} / ${totalStoresCount}`, icon: Store, chip: 'bg-purple-50 text-[#581c87]', loading: locationsQ.isLoading }, - { title: 'REGION FULFILLMENT', display: regionFulfillmentPct == null ? 'β€”' : `${regionFulfillmentPct.toFixed(1)}%`, icon: Sparkles, chip: 'bg-emerald-50 text-emerald-600', loading: summaryQ.isLoading }, - { title: 'MONTHLY REVENUE', display: money(monthlyRevenue), icon: Wallet, chip: 'bg-sky-50 text-sky-600', loading: insightQ.isLoading }, - { title: 'MONTHLY PROFIT', display: money(monthlyProfit), icon: TrendingUp, chip: 'bg-emerald-50 text-emerald-600', loading: insightQ.isLoading }, + { + title: 'ACTIVE OUTLETS', + display: `${activeStoresCount} / ${totalStoresCount}`, + sub: `${activePct}% of the network is live`, + icon: Store, + bar: 'from-purple-500 to-indigo-500', + chip: 'bg-purple-50 text-purple-650 ring-purple-100', + loading: locationsQ.isLoading, + }, + { + title: 'REGION FULFILLMENT', + display: regionFulfillmentPct == null ? 'β€”' : `${regionFulfillmentPct.toFixed(1)}%`, + sub: `${ordersDelivered.toLocaleString('en-IN')} of ${ordersTotal.toLocaleString('en-IN')} orders delivered`, + icon: Activity, + bar: 'from-indigo-500 to-sky-500', + chip: 'bg-indigo-50 text-indigo-600 ring-indigo-100', + loading: summaryQ.isLoading, + }, + { + title: 'MONTHLY REVENUE', + display: money(monthlyRevenue), + sub: 'Gross billed Β· month-to-date', + icon: Wallet, + bar: 'from-sky-500 to-cyan-500', + chip: 'bg-sky-50 text-sky-600 ring-sky-100', + loading: insightQ.isLoading, + }, + { + title: 'MONTHLY PROFIT', + display: money(monthlyProfit), + sub: 'Net margin Β· month-to-date', + icon: TrendingUp, + bar: 'from-emerald-500 to-teal-500', + chip: 'bg-emerald-50 text-emerald-600 ring-emerald-100', + loading: insightQ.isLoading, + }, ]; const statusRows = [ @@ -97,35 +129,57 @@ export default function DashboardView({ searchQuery }: DashboardViewProps) { return (
- {/* Scope banner */} -
-
- - - Live operations data for {tenantName} Β· {fromdate} β†’ {todate} - + {/* ── Immersive Executive Banner (cover image + slateβ†’purple gradient overlay) ── */} +
+ {/* Cover image background & decorative glow */} +
+ Executive operations dashboard +
+
+
-
- {/* Header */} -
-
-

Executive Command Center

-
-

Month-to-date order operations, pulled live from the API.

- {loading ? ( - - Loading… + {/* Content row */} +
+
+

+ Executive Command Center + + Live Core - ) : errored ? ( - - Live data unavailable - - ) : ( - - Live Β· {tenantName} - - )} +

+

+ Month-to-date order operations for {tenantName}, pulled live from the API. +

+ +
+ {loading ? ( + + Syncing live data… + + ) : errored ? ( + + Live data unavailable + + ) : ( + + Live Β· {tenantName} + + )} +
+
+ + {/* Reporting scope panel */} +
+
+ + {fromdate} β†’ {todate} +
+ Month-to-date reporting scope
@@ -144,23 +198,31 @@ export default function DashboardView({ searchQuery }: DashboardViewProps) {
)} - {/* KPI cards β€” all live from getordersummary */} + {/* KPI cards β€” all live from getordersummary / getinvoiceinsight */}
{kpis.map((kpi) => { const Icon = kpi.icon; return (
-
- + {/* Gradient accent bar */} + +
+
+ +
+
-

+

{kpi.title}

-

- {kpi.loading ? … : kpi.display} +

+ {kpi.loading ? … : kpi.display} +

+

+ {kpi.sub}

); @@ -170,115 +232,140 @@ export default function DashboardView({ searchQuery }: DashboardViewProps) { {/* Order status + store locations */}
{/* Store Node Status donut (live) */} -
-
-

Store Outlet Status

-

Active share of all registered store nodes.

+
+
+
+ +
+
+

Store Outlet Status

+

Active share of all registered nodes.

+
-
-
- - +
+
+ {/* soft glow behind the ring */} +
+ + + + + + + +
- {activePct}% - Active + {activePct}% + Active
-
+
{statusRows.map((r) => ( -
- +
+ {r.label} - {r.value.toLocaleString('en-IN')} + {r.value.toLocaleString('en-IN')}
))} -
- Total Nodes - {totalStoresCount.toLocaleString('en-IN')} +
+ Total Nodes + {totalStoresCount.toLocaleString('en-IN')}
{/* Store locations (live) */} -
-
-

- Store Locations +
+
+

+ + + + Store Locations

- + {locationsQ.isLoading ? 'Loading…' : `${locations.length} Outlet${locations.length === 1 ? '' : 's'}`}
{locationsQ.isLoading ? ( -
Loading store locations…
+
Loading store locations…
) : locations.length === 0 ? ( -
No store locations found for this tenant.
+
No store locations found for this tenant.
) : ( -
+
{locations.map((loc, i) => { const sum = summaries.find((s) => s.locationid === Number(loc.locationid)); const deliveries = sum?.delivered ?? 0; const orders = Math.max(sum?.delivered ?? 0, sum?.total ?? 0); - + const isActive = str(loc.status).toLowerCase() === 'active'; + const name = str(loc.locationname); + return (
-
-

{str(loc.locationname)}

-

- - {str(loc.address) || `${str(loc.suburb)}, ${str(loc.city)}`} -

- {str(loc.contactno) && ( -

- - {str(loc.contactno)} +

+ {/* Outlet initial badge */} +
+ {name.slice(0, 2) || 'β€”'} +
+
+

{name}

+

+ + {str(loc.address) || `${str(loc.suburb)}, ${str(loc.city)}`}

- )} - - {/* Node-specific Orders and Dispatches */} -
- - {orders} Orders - - - {deliveries} Dispatched - - {orders > 0 && ( - - {Math.round((deliveries / orders) * 100)}% Fulfilled - + {str(loc.contactno) && ( +

+ + {str(loc.contactno)} +

)} + + {/* Node-specific Orders and Dispatches */} +
+ + {orders} Orders + + + {deliveries} Dispatched + + {orders > 0 && ( + + {Math.round((deliveries / orders) * 100)}% Fulfilled + + )} +
+ {str(loc.status) || 'β€”'}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c5337aa..f58bb59 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -4,29 +4,29 @@ */ import React, { useState, useRef, useEffect } from 'react'; -import { Menu, Plus, HelpCircle, LogOut } from 'lucide-react'; +import { Menu, HelpCircle, LogOut, ChevronDown, Mail } from 'lucide-react'; import { MainSection } from '../types'; interface HeaderProps { - currentSection: MainSection; - setCurrentSection: (section: MainSection) => void; - isCoimbatoreView: boolean; + // Admin nav context β€” unused by the bar itself, optional so the Header can be + // reused by the user store page which has no MainSection routing. + currentSection?: MainSection; + setCurrentSection?: (section: MainSection) => void; + isCoimbatoreView?: boolean; onToggleSidebar: () => void; isSidebarOpen: boolean; - onNewReportClick: () => void; onHelpClick: () => void; onLogoutClick: () => void; + /** Signed-in user shown in the profile dropdown. */ + profile: { name: string; role: string; email: string }; } export default function Header({ - currentSection, - setCurrentSection, - isCoimbatoreView, onToggleSidebar, isSidebarOpen, - onNewReportClick, onHelpClick, - onLogoutClick + onLogoutClick, + profile }: HeaderProps) { const [showProfileDropdown, setShowProfileDropdown] = useState(false); const profileRef = useRef(null); @@ -47,12 +47,14 @@ export default function Header({ }; }, [showProfileDropdown]); - const profile = { - name: 'Suresh Kumar', - role: 'Operations Director', - email: 'suresh.k@nearledaily.com', - avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=150&q=80' - }; + const initials = + profile.name + .split(' ') + .map((w) => w[0]) + .filter(Boolean) + .slice(0, 2) + .join('') + .toUpperCase() || 'NA'; return (
@@ -83,52 +85,74 @@ export default function Header({
{showProfileDropdown && ( -
-
-

{profile.name}

-

{profile.role}

+
+ {/* Gradient profile header */} +
+
+
+ + + {initials} + + + +
+

{profile.name}

+ + {profile.role} + +
+
+
+ + {profile.email} +
-
-
-

Email

-

{profile.email}

-
- {/* Account actions (moved here from the sidebar) */} -
- - - -
+ {/* Account actions (moved here from the sidebar) */} +
+ +
+
)} diff --git a/src/components/InventoryView.tsx b/src/components/InventoryView.tsx index db86b21..864a8ad 100644 --- a/src/components/InventoryView.tsx +++ b/src/components/InventoryView.tsx @@ -19,25 +19,26 @@ import { Trash2, PackageCheck, ShieldCheck, - Zap, Tag, UploadCloud, FileSpreadsheet, Palette, - ShoppingBag, Info, X, Server, ChevronDown, ChevronUp, - RotateCw, CheckCircle } from 'lucide-react'; -import { ProductMatrixItem, ImportLog } from '../types'; -import { initialImportLogs } from '../data'; -import { useFiestaTenantLocations, useFiestaStoresStock } from '../services/fiestaQueries'; +import { ProductMatrixItem } from '../types'; +import { + useFiestaTenantLocations, + useFiestaStoresStock, + useFiestaProductCategories, +} from '../services/fiestaQueries'; import { FIESTA_TENANT_ID, str as fstr } from '../services/fiestaApi'; import { stockRowToProduct, stockRowToInventory } from '../services/fiestaMappers'; +import AwaitingApi from './AwaitingApi'; type StockRow = Record; const rowId = (r: StockRow) => String(r.productid ?? '') || String(r.productname ?? ''); @@ -78,7 +79,6 @@ export default function InventoryView({ // Global catalog = deduped union of every outlet's products, plus anything the // admin adds/imports in-session. Seeded once from the live data. const [products, setProducts] = useState([]); - const [importLogs, setImportLogs] = useState(initialImportLogs); const [seeded, setSeeded] = useState(false); const allStoreRows = storesStock.flatMap((s) => s.rows); @@ -98,8 +98,8 @@ export default function InventoryView({ const [showAddProductModal, setShowAddProductModal] = useState(false); const [outletFilter, setOutletFilter] = useState<'all' | 'alerts'>('all'); const [outletSearch, setOutletSearch] = useState(''); - const [restockedOverrides, setRestockedOverrides] = useState>>({}); - const [loadingOutlets, setLoadingOutlets] = useState>({}); + // Regional Hub Stocks is read-only for admins β€” overrides remain empty (no restock actions). + const [restockedOverrides] = useState>>({}); const [expandedHubs, setExpandedHubs] = useState>({}); // Memoize storesStock query results merged with simulated restock overrides @@ -155,89 +155,11 @@ export default function InventoryView({ }; }, [storesStockWithOverrides]); - // Simulated restock dispatch handler - const handleRestockOutlet = (locationId: number, storeRows: any[], locationName: string) => { - setLoadingOutlets(prev => ({ ...prev, [locationId]: true })); - - setTimeout(() => { - setRestockedOverrides(prev => { - const currentOverrides = prev[locationId] || {}; - const newOverrides = { ...currentOverrides }; - - storeRows.forEach(row => { - const sku = `SKU-${String(row.productid ?? '') || String(row.productname ?? '')}`; - newOverrides[sku] = 200; // Restock to safe optimal level (>= 120) - }); - - return { - ...prev, - [locationId]: newOverrides - }; - }); - - setLoadingOutlets(prev => ({ ...prev, [locationId]: false })); - - const timestamp = new Date().toLocaleTimeString(); - setImportLogs(prev => [ - { - id: String(Date.now()), - timestamp, - file: 'SUPPLY_CHAIN_API', - status: 'SUCCESS', - count: storeRows.length, - note: `AUTO-RESTOCK: Dispatched emergency shipment to ${locationName}. Synchronized ${storeRows.length} SKUs to 200 units.` - }, - ...prev - ]); - }, 1500); - }; - - // Simulated single SKU restock handler - const handleRestockSKU = (locationId: number, row: any, locationName: string) => { - if (!row) return; - const sku = `SKU-${String(row.productid ?? '') || String(row.productname ?? '')}`; - const prodName = String(row.productname || 'Unnamed product'); - - setRestockedOverrides(prev => { - const currentOverrides = prev[locationId] || {}; - return { - ...prev, - [locationId]: { - ...currentOverrides, - [sku]: 200 - } - }; - }); - - const timestamp = new Date().toLocaleTimeString(); - setImportLogs(prev => [ - { - id: String(Date.now()), - timestamp, - file: 'SUPPLY_CHAIN_API', - status: 'SUCCESS', - count: 1, - note: `SKU-RESTOCK: Restocked ${prodName} (${sku}) at ${locationName} to 200 units.` - }, - ...prev - ]); - }; - // CSV Textarea input const [csvText, setCsvText] = useState( "Name, SKU, Category, Price, InitialStock\nAmma Ghee Pure Butter, GHEE-AMMA-1L, Groceries / Oils, 640, 200\nBhavani Ponni Sona Rice, ST-SONA-25K, Staples / Rice, 1350, 150" ); - // Brand designs state - const [brandStyle, setBrandStyle] = useState({ - themeName: 'Coimbatore Kaveri Org', - primaryColor: '#16a34a', // Emerald - secondaryColor: '#f59e0b', // Amber - bagLabel: 'Freshly Harvested from Tamil Soil', - isEcoVerified: true, - stickerPattern: 'radial' - }); - // Form state for individual adding const [newProduct, setNewProduct] = useState({ name: '', @@ -248,6 +170,16 @@ export default function InventoryView({ image: 'https://images.unsplash.com/photo-1542838132-92c53300491e?auto=format&fit=crop&q=80&w=200' }); + // Live product categories (for the Add-Product modal dropdown). + const productCategoriesQ = useFiestaProductCategories(); + const productCategoryNames = useMemo( + () => + (productCategoriesQ.data ?? []) + .map((c) => fstr(c.categoryname)) + .filter((name): name is string => Boolean(name)), + [productCategoriesQ.data], + ); + // Categories derived from the live catalog (falls back to ALL only). const categorySet = new Set(); products.forEach((p) => categorySet.add(p.category)); @@ -342,78 +274,12 @@ export default function InventoryView({ if (parsedCount > 0) { setProducts(prev => [...newProds, ...prev]); - - const logEntry: ImportLog = { - timestamp: new Date().toLocaleTimeString() + ' (IST)', - batchRef: `#IMP_CSV_${Math.floor(1000 + Math.random() * 9000)}`, - type: 'CSV Catalogue Import', - source: 'Console Upload', - result: `SUCCESS (Parsed ${parsedCount} rows)`, - status: 'SUCCESS' - }; - setImportLogs([logEntry, ...importLogs]); alert(`Synchronized ${parsedCount} regional products into Catalog database successfully!`); } else { alert('All the specified SKU codes are already active in the catalog ledger.'); } }; - // Preset import trigger - const handleImportPreset = (presetName: string, itemsList: Array<{name: string, sku: string, cat: string, price: number, stock: number, img: string}>) => { - let imported = 0; - const newProds: ProductMatrixItem[] = []; - - itemsList.forEach((itm) => { - if (!products.some(p => p.sku === itm.sku)) { - newProds.push({ - id: String(products.length + newProds.length + 20), - name: itm.name, - sku: itm.sku, - unitsSold: Math.floor(Math.random() * 45 + 15), - revenue: Math.floor(Math.random() * 20000 + 4000), - stockStatus: 'Healthy', - trend: 'up', - image: itm.img, - category: itm.cat, - exposure: 'All Outlets', - verified: true - }); - imported++; - } - }); - - if (imported > 0) { - setProducts(prev => [...newProds, ...prev]); - - const logEntry: ImportLog = { - timestamp: new Date().toLocaleTimeString() + ' (IST)', - batchRef: `#IMP_PST_${Math.floor(1000 + Math.random() * 9000)}`, - type: `${presetName} Import`, - source: 'Corporate Cloud Feed', - result: `SUCCESS Onboarded (${imported} SKUs)`, - status: 'SUCCESS' - }; - setImportLogs([logEntry, ...importLogs]); - alert(`Successfully mapped and onboarded ${imported} brand SKUs from "${presetName}"!`); - } else { - alert('All elements of this retail catalog preset are already assigned.'); - } - }; - - // Nilgiris Presets - const nilgirisDairy = [ - { name: 'Ooty Hills Creamery Butter 500g', sku: 'DY-OOT-BTR', cat: 'Groceries / Oils', price: 340, stock: 210, img: 'https://images.unsplash.com/photo-1589985270826-4b7bb135bc9d?auto=format&fit=crop&q=80&w=200' }, - { name: 'Nilgiris Mountain Farm Cheese 250g', sku: 'DY-NIL-CHS', cat: 'Groceries / Oils', price: 460, stock: 120, img: 'https://images.unsplash.com/photo-1486887396153-fa416525c108?auto=format&fit=crop&q=80&w=200' }, - { name: 'Aavin Premium Ghee Tin 1L', sku: 'DY-AAV-GHEE', cat: 'Groceries / Oils', price: 680, stock: 180, img: 'https://images.unsplash.com/photo-1542838132-92c53300491e?auto=format&fit=crop&q=80&w=200' } - ]; - - // Coimbatore Crops - const cbeHeritage = [ - { name: 'Bhavani Premium Boiled Rice 10kg', sku: 'ST-BHV-RICE', cat: 'Staples / Rice', price: 740, stock: 350, img: 'https://images.unsplash.com/photo-1586201375761-83865001e31c?auto=format&fit=crop&q=80&w=200' }, - { name: 'Pollachi Clean Gram Dhal 2kg', sku: 'ST-POL-DHAL', cat: 'Staples / Rice', price: 185, stock: 240, img: 'https://images.unsplash.com/photo-1596040033229-a9821ebd058d?auto=format&fit=crop&q=80&w=200' }, - { name: 'Pure Wood Pressed Gingelly Oil 1L', sku: 'ST-OIL-WOOD', cat: 'Groceries / Oils', price: 395, stock: 190, img: 'https://images.unsplash.com/photo-1474979266404-7eaacbcd87c5?auto=format&fit=crop&q=80&w=200' } - ]; - return (
@@ -422,7 +288,7 @@ export default function InventoryView({
{/* ── Immersive Analytics Banner (With Catalog Cover Image & Slate Gradient Overlay) ── */} -
+
{/* Cover Image Background & Decor */}
{/* Content Row */} -
+

- Product Catalog Command Center + Product Catalog Global Sync @@ -710,19 +576,22 @@ export default function InventoryView({ {/* Elegant Header Row */}
-
-
-

- Regional Hub Stocks -

- - - Live Sync - +
+
+ +
+
+
+

Regional Hub Stocks

+ + + Live Sync + +
+

+ Real-time inventory levels and capacity balance across {locations.length} regional outlets. +

-

- Real-time inventory levels and capacity balance across {locations.length} regional outlets. -

{/* Controls: Search + Filters */} @@ -779,23 +648,29 @@ export default function InventoryView({
{/* Quick Metrics Strip */} -
-
- Active Outlets - {locations.length} -
-
- Optimal Hubs - {locations.length - storeAlertsData.alertOutletsCount} -
-
- Low Stock Items - {storeAlertsData.lowStockCount} -
-
- Critical Alerts - {storeAlertsData.criticalCount} -
+
+ {[ + { label: 'Active Outlets', value: locations.length, icon: Server, chip: 'bg-purple-50 text-purple-650 ring-purple-100', value_cls: 'text-slate-900' }, + { label: 'Optimal Hubs', value: locations.length - storeAlertsData.alertOutletsCount, icon: CheckCircle, chip: 'bg-emerald-50 text-emerald-600 ring-emerald-100', value_cls: 'text-emerald-600' }, + { label: 'Low Stock Items', value: storeAlertsData.lowStockCount, icon: TrendingDown, chip: 'bg-amber-50 text-amber-600 ring-amber-100', value_cls: 'text-amber-600' }, + { label: 'Critical Alerts', value: storeAlertsData.criticalCount, icon: AlertTriangle, chip: 'bg-rose-50 text-rose-600 ring-rose-100', value_cls: 'text-rose-600' }, + ].map((m) => { + const MIcon = m.icon; + return ( +
+
+ +
+
+ {m.label} + {m.value} +
+
+ ); + })}
{(() => { @@ -833,10 +708,14 @@ export default function InventoryView({ const meta = locations.find((l) => l.locationid === store.locationid); const status = meta?.status ?? 'Active'; - const statusDotColor = hasAlert - ? criticalItemsCount > 0 ? 'bg-rose-500' : 'bg-amber-500' + const statusDotColor = hasAlert + ? criticalItemsCount > 0 ? 'bg-rose-500' : 'bg-amber-500' : 'bg-emerald-500'; + const statusChip = hasAlert + ? criticalItemsCount > 0 ? 'bg-rose-50 text-rose-600 ring-rose-100' : 'bg-amber-50 text-amber-600 ring-amber-100' + : 'bg-emerald-50 text-emerald-600 ring-emerald-100'; + const optimalPct = totalItems > 0 ? (optimalCount / totalItems) * 100 : 0; const lowPct = totalItems > 0 ? (lowCount / totalItems) * 100 : 0; const criticalPct = totalItems > 0 ? (criticalItemsCount / totalItems) * 100 : 0; @@ -848,72 +727,71 @@ export default function InventoryView({ }); return ( -
- - {/* Loading Overlay */} - {loadingOutlets[store.locationid] && ( -
-
-
-
-
-
-
-

Replenishing Hub...

-

Dispatching supply batch to {store.locationname}

-
+
+ + {/* Card Header */} +
+
+
+ +
+
+

+ {store.locationname} +

+

+ {totalItems} items Β· {totalUnits.toLocaleString('en-IN')} units +

- )} - - {/* Card Header (Clean & borderless) */} -
-
-

- - {store.locationname} -

-

- {totalItems} items Β· {totalUnits.toLocaleString('en-IN')} units -

-
- 0 - ? 'text-rose-600 bg-rose-50' - : 'text-amber-700 bg-amber-50' - : 'text-emerald-600 bg-emerald-50' + ? criticalItemsCount > 0 + ? 'text-rose-600 bg-rose-50 border border-rose-100' + : 'text-amber-700 bg-amber-50 border border-amber-100' + : 'text-emerald-600 bg-emerald-50 border border-emerald-100' }`}> + {hasAlert ? criticalItemsCount > 0 ? 'Critical' : 'Low Stock' : 'Optimal'}
{/* Card Body */} -
- +
+ {/* Segmented Stock Health Distribution */} -
- {criticalPct > 0 && ( -
- )} - {lowPct > 0 && ( -
- )} - {optimalPct > 0 && ( -
- )} +
+
+ Stock Health + + {criticalItemsCount > 0 && {criticalItemsCount} crit} + {lowCount > 0 && {lowCount} low} + {optimalCount} ok + +
+
+ {criticalPct > 0 && ( +
+ )} + {lowPct > 0 && ( +
+ )} + {optimalPct > 0 && ( +
+ )} +
{/* Capacity utilization indicator */} -
-
+
+
Capacity Utilised - {Math.round(capacityPct)}% + {Math.round(capacityPct)}%
-
-
+
85 ? 'bg-rose-500' : 'bg-purple-650' + capacityPct > 85 ? 'bg-rose-500' : 'bg-gradient-to-r from-purple-500 to-indigo-500' }`} style={{ width: `${capacityPct}%` }} /> @@ -931,11 +809,10 @@ export default function InventoryView({ ) : (
{sortedItems.map((it, idx) => { - const rawRow = store.rows.find(r => `SKU-${String(r.productid ?? '') || String(r.productname ?? '')}` === it.sku); const isLow = it.status !== 'Optimal'; return ( -
+
- -
- - {it.stockLevel} - - {isLow && ( - - )} -
+ + + {it.stockLevel} +
); })} @@ -972,20 +838,18 @@ export default function InventoryView({
- {/* Card Footer actions */} + {/* Card Footer β€” read-only status (admins cannot edit hub stock) */}
{hasAlert ? `${criticalItemsCount + lowCount} items need attention` : 'All items optimal'} {hasAlert ? ( - + 0 ? 'text-rose-600' : 'text-amber-700' + }`}> + {criticalItemsCount > 0 ? 'Critical' : 'Low Stock'} + ) : ( Stocked @@ -1013,45 +877,7 @@ export default function InventoryView({

Cooperative Catalog Presets

-
- - {/* Preset 1 */} -
-
- Cooperative Dairy -

Nilgiris Dairy Fresh Pack

-

3 High-Margin Butter & Cheese SKUs

-
-
- CBE-COOP-04 - -
-
- - {/* Preset 2 */} -
-
- Agricultural Feed -

Coimbatore Heritage Grains

-

3 Premium Boiled Rice & Oils

-
-
- TAMIL-AGRI-09 - -
-
- -
+
{/* Custom CSV Parsing Box */} @@ -1097,26 +923,7 @@ export default function InventoryView({ COIMBATORE_ERP_V4
-
- {importLogs.map((log, idx) => ( -
-
-
- {log.batchRef} - {log.timestamp} -
-

- {log.type} via {log.source} -

-

{log.result}

-
- - - {log.status} - -
- ))} -
+
@@ -1130,115 +937,7 @@ export default function InventoryView({

Packaging Branding Studio

-
- - {/* Studio Control 1 */} -
- - setBrandStyle({ ...brandStyle, themeName: e.target.value })} - className="w-full border border-[#e2e8f0] rounded-lg p-sm bg-[#f8fafc] focus:bg-white outline-none focus:ring-1 focus:ring-[#581c87] font-semibold text-zinc-700" - /> -
- - {/* Studio Control 2 */} -
-
- -
- setBrandStyle({ ...brandStyle, primaryColor: e.target.value })} - className="w-8 h-8 rounded border border-zinc-200 cursor-pointer bg-transparent" - /> - {brandStyle.primaryColor} -
-
- -
- -
- setBrandStyle({ ...brandStyle, secondaryColor: e.target.value })} - className="w-8 h-8 rounded border border-zinc-200 cursor-pointer bg-transparent" - /> - {brandStyle.secondaryColor} -
-
-
- - {/* Studio Control 3 */} -
- - setBrandStyle({ ...brandStyle, bagLabel: e.target.value })} - className="w-full border border-[#e2e8f0] rounded-lg p-sm bg-[#f8fafc] focus:bg-white outline-none focus:ring-1 focus:ring-[#581c87] font-semibold text-zinc-700" - /> -
- - {/* Studio Control 4 */} -
-
-

Sustainability Seal

-

Include Coimbatore eco certification stamp

-
- -
- - {/* Interactive Dynamic Checkout Jute Bag Preview Canvas */} -
- - Package Bag Design Preview - - -
- {/* Realistic Jute Texture Overlay simulation */} -
- - {/* Hanging handle simulation */} -
- -
- - {brandStyle.themeName || 'nearledaily Fresh'} - -
-
- -
- - - {brandStyle.bagLabel || 'Grown with Pride'} - -
- -
- 100% ORGANIC - {brandStyle.isEcoVerified && ( - - CBE-ECO - - )} -
-
-
- -
+
@@ -1302,10 +1001,13 @@ export default function InventoryView({ onChange={(e) => setNewProduct({ ...newProduct, category: e.target.value })} className="w-full border border-[#e2e8f0] rounded-lg p-2 bg-[#f8fafc] focus:bg-white outline-none" > - - - - + {/* Keep the form's default selection valid even if it isn't in the live list. */} + {!productCategoryNames.includes(newProduct.category) && ( + + )} + {productCategoryNames.map((name) => ( + + ))}
diff --git a/src/components/LoginView.tsx b/src/components/LoginView.tsx new file mode 100644 index 0000000..0c366b4 --- /dev/null +++ b/src/components/LoginView.tsx @@ -0,0 +1,296 @@ +/** + * @license + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + ShieldCheck, + Mail, + Lock, + ArrowRight, + Eye, + EyeOff, + Loader2, +} from 'lucide-react'; +import { checkEmailRequest } from '../services/auth'; +import type { AuthUser } from '../services/auth'; +import { useLogin } from '../services/fiestaQueries'; + +interface LoginViewProps { + /** Called with the authenticated user once credentials are verified. */ + onLogin: (user: AuthUser) => void; +} + +export default function LoginView({ onLogin }: LoginViewProps) { + // A single login form. The backend's role on the verified user decides the + // workspace (admin vs user) the account actually lands on. + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [showPassword, setShowPassword] = useState(false); + const [error, setError] = useState(''); + const [step, setStep] = useState<'email' | 'password'>('email'); + const [checkingEmail, setCheckingEmail] = useState(false); + + const login = useLogin(); + const loading = login.isPending; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (loading || checkingEmail) return; + + if (step === 'email') { + if (!email.trim()) { + setError('Please enter your email.'); + return; + } + setError(''); + setCheckingEmail(true); + try { + const emailExists = await checkEmailRequest(email); + if (emailExists) { + setStep('password'); + } else { + setError('Email not found. Please try again.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'Unable to verify email. Please try again.'); + } finally { + setCheckingEmail(false); + } + } else { + if (!password.trim()) { + setError('Please enter your password.'); + return; + } + setError(''); + // Verify credentials against the backend via the TanStack mutation. Only an + // exact match resolves; the returned role routes admin vs user workspace. + login.mutate( + { email, password }, + { + onSuccess: (user) => onLogin(user), + onError: (err) => + setError(err instanceof Error ? err.message : 'Sign in failed. Please try again.'), + }, + ); + } + }; + + return ( +
+ {/* ── Left brand / hero panel (desktop only) ── */} +
+ {/* Layered ambient glows */} +
+
+
+ {/* Subtle dot-grid texture */} +
+ +
+ {/* Logo */} +
+ nearledaily +
+ + {/* Hero */} +
+ {/* Eyebrow */} + + + Secure Merchant Console + + +

+ All Operations +
+ In One Console +

+

+ Monitor regional hubs, track live order operations, and manage your entire store network from a single command center. +

+ + {/* Glassmorphic live-snapshot preview card */} +
+
+ Live Operations + + + LIVE + +
+ +
+
+

2,480

+

Orders today

+
+
+

98.6%

+

Fulfillment

+
+
+ + {/* Mini bar chart */} +
+ {[45, 62, 38, 70, 52, 80, 60, 90, 55, 74].map((h, i) => ( +
+ ))} +
+
+
+ + {/* Trust stats + copyright */} +
+
+ {[ + { v: '120+', l: 'Regional hubs' }, + { v: '99.9%', l: 'Platform uptime' }, + { v: '24/7', l: 'Live monitoring' }, + ].map((s) => ( +
+

{s.v}

+

{s.l}

+
+ ))} +
+

+ Β© 2026 nearledaily Β· All rights reserved +

+
+
+
+ + {/* ── Right form panel ── */} +
+
+ {/* Logo / brand (mobile) */} +
+ nearledaily +
+ + {/* Heading */} +
+

Welcome back

+

Sign in to your nearledaily workspace to continue.

+
+ +
+ {/* Email or username (the API's `authname` accepts either) */} +
+
+ + {step === 'password' && ( + + )} +
+
+ + setEmail(e.target.value)} + placeholder="you@nearledaily.com" + className="w-full h-12 pl-10 pr-4 bg-slate-50 border border-slate-200 rounded-xl text-sm text-slate-800 placeholder-slate-400 focus:outline-none focus:border-purple-500 focus:bg-white focus:ring-4 focus:ring-purple-500/10 transition-all disabled:opacity-75 disabled:cursor-not-allowed" + /> +
+
+ + {/* Password */} + {step === 'password' && ( +
+ +
+ + setPassword(e.target.value)} + placeholder="β€’β€’β€’β€’β€’β€’β€’β€’" + className="w-full h-12 pl-10 pr-11 bg-slate-50 border border-slate-200 rounded-xl text-sm text-slate-800 placeholder-slate-400 focus:outline-none focus:border-purple-500 focus:bg-white focus:ring-4 focus:ring-purple-500/10 transition-all" + /> + +
+
+ )} + + {error && ( +

+ {error} +

+ )} + + {/* Options row */} + {step === 'password' && ( +
+ + +
+ )} + + {/* Submit */} + +
+ + {/* Helper note */} +

+ Your workspace is set automatically based on your account access. +

+
+
+
+ ); +} diff --git a/src/components/OperationsView.tsx b/src/components/OperationsView.tsx index 8491a58..8826c7a 100644 --- a/src/components/OperationsView.tsx +++ b/src/components/OperationsView.tsx @@ -19,12 +19,9 @@ import { XCircle, FolderSync, UploadCloud, - FileCheck, Download, - AlertOctagon, X, } from 'lucide-react'; -import { initialImportLogs } from '../data'; import { InventoryItem } from '../types'; import { useFiestaStockStatement, @@ -32,6 +29,7 @@ import { } from '../services/fiestaQueries'; import { FIESTA_TENANT_ID, FIESTA_PRIMARY_LOCATION_ID, num as fnum, str as fstr } from '../services/fiestaApi'; import { stockRowToProduct, stockRowToInventory } from '../services/fiestaMappers'; +import AwaitingApi from './AwaitingApi'; interface OperationsViewProps { searchQuery: string; @@ -66,7 +64,6 @@ export default function OperationsView({ searchQuery, isCoimbatoreView }: Operat // Dynamic state arrays for interaction (seeded from live data once it loads). const [inventoryList, setInventoryList] = useState([]); const [productList, setProductList] = useState[]>([]); - const [importLogs, setImportLogs] = useState(initialImportLogs); useEffect(() => { if (stockQ.data) { @@ -253,10 +250,7 @@ export default function OperationsView({ searchQuery, isCoimbatoreView }: Operat

Fulfillment Health

-

98.4%

-
-
-
+
@@ -376,12 +370,14 @@ export default function OperationsView({ searchQuery, isCoimbatoreView }: Operat Forecast Efficiency -

92%

-

- AI-Driven automated replenishment is saving an estimated β‚Ή1.9L/week in system overstock costs. -

+
- + {/* Embedded SVG graphic visual */}
@@ -451,7 +447,7 @@ export default function OperationsView({ searchQuery, isCoimbatoreView }: Operat Master Assortment Catalogue

- Global inventory master list and exposure levels across 4,200 nodes. + Global inventory master list and exposure levels across {productList.length.toLocaleString('en-IN')} nodes.

@@ -549,19 +545,10 @@ export default function OperationsView({ searchQuery, isCoimbatoreView }: Operat {activeSubTab === 'import' && (
{/* Upload panel zone */} -
{ const fileRef = prompt('Enter CSV filename representation path:'); if (fileRef) { - const logsToAdd = { - timestamp: 'Just now', - batchRef: `#IMP_0922_${String.fromCharCode(65 + Math.floor(Math.random() * 26))}`, - type: 'Inventory Sync', - source: fileRef, - result: `SUCCESS (98 Rows verified)`, - status: 'SUCCESS' as const - }; - setImportLogs([logsToAdd, ...importLogs]); alert('Uploaded successfully. Metadata schema verification committed.'); } }} @@ -602,50 +589,7 @@ export default function OperationsView({ searchQuery, isCoimbatoreView }: Operat Interactive Schema Validator -
-
- -
-
Verification Rule Passed
-

Primary header nodes align perfectly with Master specification v2.8.

-
-
- -
- -
-
14 Duplicate SKUs Detected
-

Duplicate item overlaps flagged inside columns 45, 82. Verify manual index configurations before finalizing commit.

- -
-
-
-
- - {/* Logs table list */} -
- Recent Import Logs - -
- {importLogs.map((log, i) => ( -
-
-

{log.batchRef}

-

{log.timestamp} β€’ {log.source}

-
- - {log.result} - -
- ))} -
+
diff --git a/src/components/OrdersDeliveriesView.tsx b/src/components/OrdersDeliveriesView.tsx index a07f9d8..982e7b3 100644 --- a/src/components/OrdersDeliveriesView.tsx +++ b/src/components/OrdersDeliveriesView.tsx @@ -12,7 +12,6 @@ import { UserCheck, MapPin, TrendingUp, - Plus, ChevronRight, Package, ArrowRight, @@ -28,9 +27,11 @@ import { useFiestaDeliveries, useFiestaDeliverySummary, useFiestaRiders, + useFiestaOrderDetails, } from '../services/fiestaQueries'; import { FIESTA_TENANT_ID, num as fnum, str as fstr, ymd } from '../services/fiestaApi'; import { deliveryRowToOrder } from '../services/fiestaMappers'; +import AwaitingApi from './AwaitingApi'; interface OrdersDeliveriesViewProps { searchQuery?: string; @@ -43,7 +44,6 @@ interface DeliveryExecutive { name: string; phone: string; status: 'Active Duty' | 'Idle' | 'Offline'; - rating: number; completedToday: number; currentZone: string; avatar: string; @@ -61,7 +61,6 @@ function riderRowToExecutive(row: Record, idx: number): Deliver name: fstr(row.fullname) || `${fstr(row.firstname)} ${fstr(row.lastname)}`.trim() || 'Rider', phone: fstr(row.contactno) || 'β€”', status: fstr(row.starttime) ? 'Active Duty' : 'Idle', - rating: 4.7, completedToday: fnum(row.completed) || fnum(row.deliverycount), currentZone: fstr(row.city) || fstr(row.vehiclename) || fstr(row.vehicleno) || 'Coimbatore', avatar: RIDER_AVATARS[idx % RIDER_AVATARS.length], @@ -141,76 +140,20 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie const activeDispatchCount = storeOrders.filter(o => o.status === 'OUT_FOR_DELIVERY').length; const completedDeliveriesCount = storeOrders.filter(o => o.status === 'DELIVERED').length; - const MOCK_NAMES = ['Aravind Swamy', 'Karthik Raja', 'Priya Mani', 'Meera Jasmine', 'Sanjay Dutt', 'Divya Spandana', 'Vijay Sethupathi', 'Nayan Thara']; - const MOCK_STREETS = ['Avarampalayam Rd', 'DB Road', 'Cross Cut Road', 'Avinashi Road', 'Trichy Road', 'NSR Road', 'Sathy Road', 'Marudhamalai Road']; - const MOCK_ITEMS = [ - { name: 'Tata Salt Premium Iodized 1kg', price: 28 }, - { name: 'Gold Winner Sunflower Oil 1L', price: 145 }, - { name: 'Britannia Marie Gold Biscuit 250g', price: 35 }, - { name: 'MTR Sambar Powder 200g', price: 85 }, - { name: 'Aavin Salted Butter 500g', price: 260 }, - { name: 'Ponni Boiled Rice 5kg', price: 380 }, - { name: 'Fresh Ooty Carrots 500g', price: 45 }, - { name: 'Nescafe Classic Coffee 100g', price: 185 }, - ]; - - const handleCreateMockOrder = () => { - const randomName = MOCK_NAMES[Math.floor(Math.random() * MOCK_NAMES.length)]; - const randomStreet = MOCK_STREETS[Math.floor(Math.random() * MOCK_STREETS.length)]; - const numItems = Math.floor(Math.random() * 3) + 1; // 1 to 3 items - const selectedItems = []; - let amount = 0; - for (let k = 0; k < numItems; k++) { - const it = MOCK_ITEMS[Math.floor(Math.random() * MOCK_ITEMS.length)]; - const qty = Math.floor(Math.random() * 2) + 1; - selectedItems.push({ name: it.name, quantity: qty, price: it.price }); - amount += it.price * qty; - } - const newId = `ORD-${Math.floor(100000 + Math.random() * 900000)}`; - const newOrder: CustomerOrder = { - id: newId, - customerName: randomName, - phone: `9${Math.floor(100000000 + Math.random() * 900000000)}`, - address: `${Math.floor(10 + Math.random() * 190)}, ${randomStreet}, Coimbatore`, - items: selectedItems, - amount, - time: new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }), - status: 'PROCESSING', - assignedRider: 'Pending Assignment', - hub: locationid ? `Outlet Node #${locationid}` : 'Coimbatore Hub', - locationid: locationid ?? 1097, + // Live line-item details for the currently selected order. The deliveries board + // only carries an itemCount; the actual basket lines come from this endpoint. + const orderDetailsQ = useFiestaOrderDetails(selectedOrder?.id ?? null); + const orderItems = (orderDetailsQ.data ?? []).map((row) => { + const quantity = fnum(row.quantity) || fnum(row.qty); + const price = fnum(row.price) || fnum(row.unitprice); + const lineTotal = fnum(row.amount) || price * quantity; + return { + name: fstr(row.productname) || fstr(row.itemname) || 'Item', + quantity, + price, + lineTotal, }; - setOrders(prev => [newOrder, ...prev]); - setSelectedOrder(newOrder); - }; - - const handleUpdateStatus = (newStatus: CustomerOrder['status']) => { - if (!selectedOrder) return; - setOrders(prev => prev.map(o => { - if (o.id === selectedOrder.id) { - const updated = { ...o, status: newStatus }; - setSelectedOrder(updated); - return updated; - } - return o; - })); - }; - - const handleAssignRider = (riderName: string) => { - if (!selectedOrder) return; - setOrders(prev => prev.map(o => { - if (o.id === selectedOrder.id) { - const updated = { - ...o, - assignedRider: riderName, - status: o.status === 'PROCESSING' ? 'CONFIRMED' : o.status - }; - setSelectedOrder(updated); - return updated; - } - return o; - })); - }; + }); return (
@@ -348,10 +291,10 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie
{/* Left List of Customer App Orders */} -
-
-
-
+
+
+
+

@@ -359,14 +302,6 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie

Interactive list of customer purchases made via client app

- -
@@ -401,11 +336,11 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie
- {/* Order item rows */} -
+ {/* Order item rows β€” flex-fills the column so the feed matches the Order Details card height */} +
{filteredOrdersList.length === 0 ? (
- No orders matching status filter found. Try another query or place a mock delivery item. + No orders matching status filter found. Try another query or adjust the date range.
) : ( filteredOrdersList.map(order => ( @@ -448,41 +383,6 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie
- - {/* Delivery Executives Fleet Section */} -
- - Coimbatore Delivery Executive Fleet status - - -
- {executives.map((ex) => ( -
-
- {ex.name} -
-

{ex.name}

-

Zone: {ex.currentZone} β€’ Rated β˜…{ex.rating}

-
-
- -
- - {ex.status} - -

Completed: {ex.completedToday}

-
-
- ))} -
-
{/* Right column β€” Order Details, shown parallel to the orders feed */} @@ -513,19 +413,24 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie
Ordered Grocery basket Items:
- {selectedOrder.items.length === 0 && ( + {orderDetailsQ.isLoading && ( +
+ Loading order line items… +
+ )} + {!orderDetailsQ.isLoading && orderItems.length === 0 && (
{selectedOrder.itemCount ?? 0} line item(s) Detail lines not loaded on board view
)} - {selectedOrder.items.map((item, idx) => ( + {orderItems.map((item, idx) => (

{item.name}

Qty: {item.quantity} x β‚Ή{item.price}

- β‚Ή{(item.price * Number(item.quantity))} + β‚Ή{item.lineTotal}
))}
@@ -535,167 +440,13 @@ export default function OrdersDeliveriesView({ searchQuery = '', isCoimbatoreVie
- {/* Interactive Status advancement controls */} -
- OPERATIONAL CONTROL - {selectedOrder.status === 'PROCESSING' && ( - - )} - {selectedOrder.status === 'CONFIRMED' && ( - - )} - {selectedOrder.status === 'OUT_FOR_DELIVERY' && ( - - )} - {selectedOrder.status === 'DELIVERED' && ( -
- Order Completed Successfully -
- )} -
- - {/* Active Rider Assignment (only if not delivered) */} - {selectedOrder.status !== 'DELIVERED' && ( -
-
- ASSIGN DELIVERY EXECUTIVE - Fleet Roster -
-
- {executives.length === 0 ? ( -

No riders currently available.

- ) : ( - executives.map(ex => { - const isAssigned = selectedOrder.assignedRider === ex.name; - return ( - - ); - }) - )} -
-
- )} - - {/* Simulated GPS map tracking path */} + {/* Live GPS route tracker β€” no rider-telemetry/GPS API yet */} {selectedOrder.status === 'OUT_FOR_DELIVERY' && (
LIVE GPS ROUTE TRACKER -
- {/* Grid background lines */} -
- - - - - - - - - {/* Route path line */} - - - {/* Hub Marker */} - - - {/* Destination Marker */} - - - - -