^)h?&$z`V-*z@5@US|c67Cc`+D;J1E8r10J(a4S-V1@AZ1zh
z8ww#uM_Yi1;&X9j5eX3mDbeR5A}Wf{MI{xK6cj`hq@_i~B@~|j3#$x=c*CHsUjM?{
z{x??iKVtvx1(@57XJx2|qYux=EL9*qZ!o?(C_YI)l_fLpG~q}&{{1Hvg4dKum>obZLu#HO
z!z#TVG$WAHQKz!rT2gat1vFRN70{V*G|ZV9mq*eblFa28$GMl9Ct}M>ph#>0pfl=5
z#f0!UzKXZd8fya0v4h@0
zY}5}d=hhnMUh!~9m*En(Ug~jWjlYu(IV$!GMk+?k0X}z
z@+l~x+J#X2&NyC_r^-71K?414*04|fK+B#^KPLe5;Q;4exLQgC!*(fZNxM;f-hyiX
zmw*2q>T_=F+J9TR$%vW|S^)bL`A+QS5F$kh^ju
zwr29VA1tNITS3XsHbxrBv~
zPIcWs`Rm6njm^~Pb})QN61nG7CVH!#ngL^Vxa=yFPk2juh5q>XXj&p#V@wRxC;~d2c)rnB
zCaUEPA@O%2%NmuI0u*-HH9qmt29F&Z=
zy}miemC}Dnz1ll_Po3_Xnb#zGRYlax{aWZSrZe)W+$=G#bugz6Vj+8RsCpHsc`qLg
z*1wbn9rA3|iGJoi20jw*+dQ9{@UNp?xN-rfZVUXpfA+*2`r+;H=eEe2-j2Pyp7x+S
z@XvIas#IDp#&|Uw=~^|$t|yGTH&$e8t+?<9oXi4m27l2{2S3;8(I}g%^5X!fc1j^}
z4vJOjk*(0KKIPICT{?};ejAKeS#j7mL`%e4vgT$8ici*ZJ9uBW9QTO~%khIlpifS$
z*Z*-_=^tbr1U=jqmDc1>SkTuNWZ|*YZ7WcxaJu7sUE`->^C)oVLo?N?wZEQ5zurgd
z!@+Y1$Dr<+=WrU)FM7Y9VG)gC_5iGdLvvi@>tK`L*Tjq~r#dR$`Cv#$5PQ9>-=a
zp}-eEi6n3xbLMrVNwYO($d6s3)SohCM*|e5-L$pPz%oyZ9MuWdk`FDV&LlEmm@v{+
zaM~xvY5CzHH3c`N|4^=_TA>ZD4BK20(j{V}%Vs4Qe*_Ec+gS7QrPD<}3$X
zm>MSC#jvWk>=pXA~Gcu33hgEBWMJG%Igz6LNC(L+mnl
zgU`A$2VHqdL-ITN@PRb`;+?a+(3oNg;;1*F0vka^l;Ps`0|32
znG=5gEb*%db%#>*b;@a=?i)N>!zTITmv@IS^e-vVDXF-cgMMqIMP%^8d$pOMO##BH
z+qB#P#a)0Y!y_htP3_*V+vCgb;SK6C;H2Mj<{lv-nqxd@EP{}#T2dt>YL!Pq`I*Fd
zAm&0|GZ6^~Qbjfwa_oH;H@FUWRF5IfVx($^h$@f#`RXh$u*Cvy(wi9+LeEckY$W^V
z)~kI&PFXl27a-E+v#<-X9glcsMaM)i`;gaMr
zqiV#rf_wxj$|h^IlRp^`&dt5u-Yfl67WUlG84LEX90EtyrE?#0
zoc!7f2ple3;e(aPJ?Z7>Uj?_rALbpBKE_5weRyMFB=9J}t;>hjCQ8#Gq^9_U@K1hm
zm=okNX0Db)2A&Q~nmEfhsz08)J?)rjf3jAArFYD$BisjSe1%2o;<2n`3_S7!G2PFNR|wcWAis!vLw%bMvMh7
z2}wAWmRR*qVb`Xo>`1$)ZUd-EfQZ4~iRgF!C1ady)vDK-WF@|431M!&U>Tr4T!Brz
zY}$V|eS(hPUueqsXMnaz&(ULW35@4wf`17ocqP
zO^VjljHmMATj>1KBk3iGv!Ai?!*8)(HG!Kg+jFOln$mS`XI*y!qzzaL>|DlWez7IB
zhwVMNJDoXfFb_QZi=&eP$Uj8MxYVbYRAg@l;n=;B3V`}oK@w#iN+&BoyD_9A*S
z9gMW`u)6bnh0rOq%ibbMhj6KE`Gl-bOoGMz;K0xN=R}lAYVRXgQefWJ;4OyJi^S0R
zZb0|$w*R0=B_FddU6899M!(1D0HpdE+MWSZ95q+Yg6r%PvrE=wVUc7dgv4wE_fo(P
zo=}tS_dDAQ;m3Ds%Fa~g&nmesg#lSEYTBDZgGTm2KO7$DYPJ$@QAX`EyHV_#)W!%1
zi!qIV_)wnu0iIQ*IW-bPM{0NnBDQIipZ9_uFr_-v+;tfNgUIR=(GGAtT#|A!lVJ^e
zMg(b=4B6mg(_jibHtXGM(g4!(mY3D+Ej%%HReJg{tm$L~qnykPh|;`YURWGn#MTO{z<;(;s7>lR00r
zq#rDyi%>IRR8xmOlTpV5rU-U>`PY=UtJ^y=dHTN3Sb00o7f-s1mVcr1aDLxjD)Df1
zxEY(gQQ{kpY87xnWkmC%Omh9ABg1)QLgl!czlr{`5o`ZUPN*eNkDj3Znd0@J$7DH+0qcz=|!
z`;WUqr%PtAfPjk_!)$rPTbbwZs(?Kf-nUn((Y6>DS@YJ+3apBHmbQ*ax}lq~SVdO0
ziY5Nod>AjU4W*;(NTuH4nrZ;yO}?}Nn$x{Xgvw6Zw#v%|J6hagq=gGr4ulg+ah
zP&cF5vfmTQEh9
zZcH2CuGz$!X&>i@CvhL!zG(t@oWrYboi(Xlnbv-xl2X7cmAkNzoaDc8M^8Q+S>eJ?
zT8oBC>i@8--7>Y35eq#TTY)YdA$-jZpN;`87NjF(vCPr}?I=Yi9OR*?kwajAC>4FN
z{)%Uoxc
zUtQE)R1&onj%PxtL#JHDm>rKtvuV{u9af_x&V)ea#AFkr`4wv0CyK>)!37W^!OvGn?u@$TWGpd*_Tf{O0pn9O*K?ohKjM(Hi${~X
zM#h!5P9!54x-c6G1mE)rbl
zgQ=-(gx2_&?KC?*l$&?^SmL-{n>ln3cyIA)-bTq;%WbkQX3e@8MqvQu<42(+j6YHi
z^;I|isv1(tU{0?`&MdE;YPi7Rq93BQUxusScbj~*pMUqnUY1wT)|stph-_8VS6frGc7SN-xy_Tm-^n@w)~3E#S%`xz1}ZdNWa561k#)v
z)@_IHOiF)SldA;e83is6A6@nVhG4^h+J=srY;!K>+Qgaq1`}bSlcgC~BYNqR^O6>F
zdM7gcWo&=Q4*uvvQMFIoiKLEVY&^cEZ;ClCP>M?IHRaI2T1~9L+UARq`%}Jyjyxnh
zGA)fU2;lzYAB5pi)EU%!cUrOSFma&^82-BkY@CBmVH=dmBDX#>Wc|=3FUI$lX~JLI
zMfdfpIakI^oMiFn%0m^!*(Bk>i3;p*Xn%IS2W<8=rO$Kz>7E^EZ|*m@24@$$?7`c}
z)kwg*k$OIieEKVYKW2P}Y3QpYw`IgsO3#glz)^SjaQXof1E9lxuQFxEv>;D|)}mJj
z89k?aQZ`lXb<>)b0|x60h7bR6go(-2pv7BdjVB%rI4q&tP73a|!s1s!-uwK*NB+iy
z7zbD|^u4?QX0Bxg{lnF*tFhwE3F1-Bhl)Z>^!>vm)28i;xMSZ^wh}f&Ug@PKso{;1
zbQ*)L(Z4LD7z=r~n@!bn<&zhDpU3@>_rIX(NM+z(UMj1IiM}=Wp~Q*Qv|mghvYEt6
z7JF)5*5ZSDL>4VaW$X&)t8Zy{4*DMUC8cg9{EwE`EL_9ydFR(TZpfw5kz-=4Tgmzv
zmGIA9^-=ePjRW9QR(W5rfoo5h@)2N%9Y&iCVCY_p!8Q*|Ov6)_40O(!dX>8lcZyyw#y
z>L7Y{W>zehuuJ{>p~<-T;R@
z!od*+bujJO98z1q%#6w3-c1uzTd_5G;Ud&d)^q7Ivka9bb(RlwnluyM?9L7wuL7UU+IT(hfr~_+nyzZ
z*Nt}Kg!8vpDQdngPZDKBC7Jx`IWiRbwn+Qnjy&{p@sXn0Q=6VskJ-c5?=!w!PXAiE
z+Z^{ZkwX5d`=YOgm0bUyYXsPGMr;Sh1$i`C=*Yy;FQ6P`@dnn4E!wN%j*2Wo88?^$
zK&`QUUses?kS$Hw*f?tPok|pcVGkp=77H8cVC8Q(M;m6oo7{(cB<}wip=FA#%Rx1V
zb6g7x#`XZi(bD+TFR#W`gwWrnpECL3W%)tj$qVSY?k+U(3ET3wOM8<1b;fW;V~x
z=(*QgtJ1o;UGrNvA%D0?jZwcr$B3TCkMS|-GJx05eMbNy>w3G^du<)IKUWtRT#9N{
zfLc3=k?|>hpp;Z1w%+)0KP8&n49tQL70oi_s3WNjuit347kS@&bZUpN9Q?_1?D~11
zIyf*8FYd2{t=~WyNy6|JMv3<#gT&8SUhZ%??rrw>^1~C||jWijl;aA^nRs3
zn8c3qi1BXE2B*Iea_4X@>bS(*-V@RK*@f^%!LuWJ@acCx%p+2r{xq^Ay~VwwBXRnZ
zHvutQTS<(!Uk~HVW%2z{@semafmx!Pm&JkYnes?3u`9Abg*iWzmuik)FW^S)vhrzb
zMB0;AQ(yvsrr9S$?brXsvCAHI%_LCeZY`NI_vE$f-kU8e>}9XyKM=os+u=+Eu7szh
zmm}X;sosv9wzoNsL(byMT^5O!7p3e=N4-iK^2E&b7C|_
zbwmctA#5-vUMnRi_Q!9|N)oH7_o+|+jVKx+9B|7I4|?~Mt6SE3gZA(&aGokS#_Vk)EF%th7Hey1VLa;p06my
zc-NyOZ=b|7f#^ceT>AWo{;nVu;qf9`>Um|GWa|m)a~0$B6H;oWPPFcUMBP{BdCo0c
z#FOMaUjv>#{nP3k-xAmEBm
z5;XzuJ-%`xw)tQhDle9p>kZ>+bu6NaRl~WdpT!64|?}g3zxpr@?C>fp*j5hrdJXV()sR-0$K#P%{>Mgi4g*LnL}
zrXT=t)l3lko@>i7vtaMkguykNt2iFQN6j?(a{v5sc4mHUf;_Xb9_)4u%EQ-<@}9lte7n-a4k``;oS=UvnuHi8px7YALi
zdZ4PjqGa_|mqri9B>!+6U1!Hvf8|R$-MRT=L6gxOFRt33Jt}J??NRbJ5i7h!AIncM
z98r>Pfp0ZmKepg7n8G4;9!O3HAh*##Bv!_*B;?D`3Q1;y0Z!=0OOCMd1j2Z)cg101
z*mySa6L;8r(o3@z9I!wufI!B-bSxFe(;xm;bGr
z>gl`Zym8nwA4(_dr+5bYpyAZFi1Gm_54)1Gx5
z#+w|?Q$%LvLXHgY?kJegH}c7t-s{$AUis>s)f{@US$Z9t__UdO)NO9MKOkml3ZdSN
zQ&4Dm@`ZGv&LC+>cfG5x1DRML7r9k01{V^I0$#WXbZ+Y7Glm1pgz+LiiMnsP
z&Gx5D0;-9{zdwImWKvpDz;cD8VMOcwNViOTpPNxR>hIl?ZXZ4=0=^hGsU~o}i2d!vzw$s^JyX3Tb`Tlr7`1hCOI#=(}
z-3~~bgWNtV%Xhaerw}OR9U!aD3)vr6MdkTf7VylaU$_^U>@4QZtI@}I0#SW>A>h4R
zS1N9U#XY8){1yD0jLG8&zzDymv)_E#y8l-Crg81Z9Tkhb?;5J9en0q$_=_sj4PRfV
z&y%CiHJq;d{h)ia!w+W8viALpXz$L=8^}B%k5aZFU~@@997~(s<6qYl4r<7*Lroe4
z3TWYye*Wphw-~%yH8qr&5X~eR7zy5G_Vm@(_c`rTIv=t8B^#!-k|V#_B>R$V8*hGY
zHb~Y94Gb%EBlPqt-dK2k7|9_k7MX
zGV-zmZy&k3A**JV<~JY_AinsaCbZW1bqZ^BKot0mo5HLI?&XQD3Z%YxQEn56y{iB6
z%PRx?2E-3_F3ufiBpJM1I4rV(NXWWvP??E243j4K3#5NBK*OKb1@srPzw|
zZt63fAq&!X8?5tNiv8V!A65{?;)AL47eg;Ca)uj1@!M5(eV_F7*`rwmf0b6%oCZDt
z?cxeZsOeiDAaVVhQbL(3g?$P95dYz+-4{IAx
za~3Sx-`_X4pz5pxj0W7$e1za?`>k$L$McuE(dU8GB0Q@#Q7ua>v%`oitCLCT2RKC&
zetz*O4I6t{I8pB*!yYrnLfdala{QR{y*X;mldptHWeA#!kw{$MTRvT*oJM9P
zWozUSlx8{q-h&{%YbC3_pryAdDG27@Ze6EIyBy(v>*&zHvL7wLv}Ud?ufi@#iYn|a
zo4aLuwan;Be&Va9wO*>>#ynJP1$PU0}l7EAwA_(JfP5E*xQlcDIDR
z{JpeTPCs|QdS6I->r#bf2B(f!*AKo?I&@Wf7%5T%bP8|n#8DYW3+}A=^A7h?mKM1c
zCg?D7vzh%Qt1{Mv1g|1+e3jiY(jinnA!e8?EA{Zr1`I?9g$x1AR@jzKgWCoyB`+fGvV$WXYP%
zQF1qZk77{a!SaxWbCEd>3fZb=Y*9+`QNG$Efr$VA3a?c1C+RYCZDKZ7Ct#
zE2yk;%TqKj+k#Qo{1!@A*o#b9-v`N~yb5(2Aij_!*36f{z(vELx`d~K;;*6Ks+cea
z!HTrLXM43Ou?Yc08|K)xqVdX_%~lfX0+Bda!9*$#nOc(fY2Q)UvS)5CO@b`ay|UPc
zAaXIg*E?gHE^8B$xOZ@u4=AJ*K^_Oh$MTUoED>HEJZnAp+JeO$e!53DLf
zxH3bWmVctT(?yc&uq2f{hgP*z9hDP|_EP%q(11ado?Euyn-6vs)py|Wia_nBnMjiY
zhVD{Q(v@6NSTnuAQcqJ%^@gK$%DR3(xss`=AG+v?N9F#3r1n}YQ0d~^(Bl0GZO&g^
z=4hX|VA9MBmXvS9hx=mt69EKu6hh>UZ2`HlR
z=x{+kg2*v!>p|~a=b9APM3!QTqQ|YnW2#FBejF*u4s@%YgcKC}+$p!Fq1(=xF|Ro|
z<$R&?tkZGNcPh&x+$qJefJ_DpZuTyXL(nmF&9A)+UWusi_p7KA0WKFc%UI%)(upc+
z>VPiTXAoz|ZSeGUa)0rHX4jD?n0a~wNZ91i8#pUbuy9J;;ldl~rz!=#dB=kkz4)_N
zEv$i}B?rFoM_q>7lw18sF$t_Zejul$dfbF-!#8b@B=L(yc}(By!(+|!WzPq{P*-a&
zPa2>3DMQ(r>#?y6%`-LRnWy)0(p|R|vI>k;MgTg-!dhh6*e@7YJ$U+JC~?1H9FRPF
z(TG7^X=L#&{!#yuHQ&5*F|Iyq|4c!lA>gkwiAF2w-%1lF3$v6_J2aOS9@c~8>4DQ$
zCyr^SC7Jn{L!hj$osy*2x%%z
z*zGROua4Z{yiaVJfw2>^*U`m3j2gpOKZE@s^vFTww}n9PDZ2~bpO={DLiO4e7d0MD
z(P8WO8|}jSb5`8tBS4Kk`ySg>#EE=g4ZI*&uiuh9=~|<gk(Otv5^CQgl*jAUikgSU{fWovRSM>!PCpd}B+LiUM96Y?1-dzdzqqz11!9Oew2QgBK(
z-VC7q4Wz%3J?vyk%m+H;vGFvTor)$?ClHwLRPnT;4Q*rf$QN(w1Et)m+t}i$prO)t
z(lm-+2?$=R5#J1yw+RStgb{)p+2&?Y{Qr9C|8}x%_gAm)&=WX=JsD;nzIMN setMount(!x));
}, []);
- const { data } = Hub.User.Get.useMe(log);
+ const data = Hub.User.Get.useMe(log);
+
const name = auth.user?.profile.preferred_username;
return <>
diff --git a/src/Components/DataGrid/Delegate.tsx b/src/Components/DataGrid/Delegate.tsx
deleted file mode 100644
index 1140ddc..0000000
--- a/src/Components/DataGrid/Delegate.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { DataGrid, DataGridBody, DataGridHeader, DataGridRow, TableColumnDefinition, TableRowId } from "@fluentui/react-components";
-
-/**
- * @author Aloento
- * @since 0.1.0
- * @version 0.2.0
- */
-export interface IDataGrid {
- Items: T[];
- Columns: TableColumnDefinition[];
- NoHeader?: true;
-}
-
-/**
- * @author Aloento
- * @since 0.1.0
- * @version 0.2.0
- */
-export function DelegateDataGrid({ Items, Columns, NoHeader }: IDataGrid) {
- return (
- item.Id}
- >
- {
- !NoHeader &&
-
- >
- {({ renderHeaderCell }) => renderHeaderCell()}
-
-
- }
-
- >
- {({ item, rowId }) => (
- key={rowId}>
- {({ renderCell }) => renderCell(item)}
-
- )}
-
-
- );
-}
diff --git a/src/Components/DataGrid/index.tsx b/src/Components/DataGrid/index.tsx
index f124612..8ec7098 100644
--- a/src/Components/DataGrid/index.tsx
+++ b/src/Components/DataGrid/index.tsx
@@ -1,27 +1,33 @@
-import { DataGrid, DataGridBody, DataGridCell, DataGridHeader, DataGridHeaderCell, DataGridRow, TableRowId } from "@fluentui/react-components";
-import { IDataGrid } from "./Delegate";
+import { DataGrid, DataGridBody, DataGridHeader, DataGridRow, SkeletonItem, TableColumnDefinition, TableRowId } from "@fluentui/react-components";
/**
* @author Aloento
- * @since 0.5.0
- * @version 0.1.0
+ * @since 0.1.0
+ * @version 0.2.1
*/
-export function DefaultDataGrid({ Items, Columns, NoHeader }: IDataGrid) {
+export interface IDataGrid {
+ Items: T[] | undefined;
+ Columns: TableColumnDefinition[];
+ NoHeader?: true;
+}
+
+/**
+ * @author Aloento
+ * @since 0.1.0
+ * @version 0.2.1
+ */
+export function DelegateDataGrid({ Items, Columns, NoHeader }: IDataGrid) {
return (
item.Id}
>
{
!NoHeader &&
-
- {({ renderHeaderCell }) => (
-
- {renderHeaderCell()}
-
- )}
+ >
+ {({ renderHeaderCell }) => renderHeaderCell()}
}
@@ -29,14 +35,12 @@ export function DefaultDataGrid({ Items, Columns,
>
{({ item, rowId }) => (
key={rowId}>
- {({ renderCell }) => (
-
- {renderCell(item)}
-
- )}
+ {({ renderCell }) => renderCell(item)}
)}
+
+ {!Items && }
- )
+ );
}
diff --git a/src/Components/Footer.tsx b/src/Components/Footer.tsx
index ace8c94..2f16c86 100644
--- a/src/Components/Footer.tsx
+++ b/src/Components/Footer.tsx
@@ -1,10 +1,10 @@
-import { makeStyles, shorthands, tokens } from "@fluentui/react-components";
+import { Text, makeStyles, shorthands, tokens } from "@fluentui/react-components";
import { Flex, NavW } from "~/Helpers/Styles";
/**
* @author Aloento
* @since 0.1.0
- * @version 0.1.0
+ * @version 0.1.1
*/
const useStyle = makeStyles({
box: {
@@ -19,8 +19,8 @@ const useStyle = makeStyles({
...shorthands.margin(0, "auto"),
},
logo: {
- width: "300px",
- filter: "brightness(200)"
+ color: "white",
+ ...shorthands.margin("64px", 0),
},
otc: {
color: "white"
@@ -29,8 +29,8 @@ const useStyle = makeStyles({
/**
* @author Aloento
- * @since 0.3.1 MusiLand
- * @version 0.1.0
+ * @since 0.1.0
+ * @version 0.2.0
*/
export function Footer(): JSX.Element {
const style = useStyle();
@@ -38,7 +38,10 @@ export function Footer(): JSX.Element {
return (
);
diff --git a/src/Components/OrderInfo.tsx b/src/Components/OrderInfo.tsx
index 6a5bb0d..a22f51e 100644
--- a/src/Components/OrderInfo.tsx
+++ b/src/Components/OrderInfo.tsx
@@ -35,7 +35,7 @@ const log = new Logger("Order", "Info");
/**
* @author Aloento
* @since 0.5.0
- * @version 0.4.1
+ * @version 0.4.2
*/
export function OrderInfo({ OrderId, Order, Admin }: IOrderInfo) {
const style = useStyles();
@@ -45,9 +45,7 @@ export function OrderInfo({ OrderId, Order, Admin }: IOrderInfo) {
onError: log.error
});
- const { data: me } = Hub.User.Get.useMe(log, {
- manual: Admin
- });
+ const me = Hub.User.Get.useMe(log);
const data = Admin ? admin : me;
diff --git a/src/Components/Setting.tsx b/src/Components/Setting.tsx
index 18b0513..366c022 100644
--- a/src/Components/Setting.tsx
+++ b/src/Components/Setting.tsx
@@ -1,5 +1,5 @@
import { Button, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Field, Input, Label, Toast, ToastBody, ToastTitle, makeStyles, tokens } from "@fluentui/react-components";
-import { useState } from "react";
+import { useEffect, useState } from "react";
import { useAuth } from "react-oidc-context";
import { Logger } from "~/Helpers/Logger";
import { ColFlex, Flex } from "~/Helpers/Styles";
@@ -39,7 +39,7 @@ const log = new Logger("Setting");
/**
* @author Aloento
* @since 0.1.0
- * @version 0.4.1
+ * @version 0.5.0
*/
export function Setting({ Open, Toggle, New }: ISetting) {
const style = useStyles();
@@ -49,17 +49,17 @@ export function Setting({ Open, Toggle, New }: ISetting) {
const [phone, setPhone] = useState();
const [address, setAddress] = useState();
- Hub.User.Get.useMe(log, {
- manual: New,
- onSuccess(data) {
- if (!data) return;
- const { Name, Phone, Address } = data;
+ const data = Hub.User.Get.useMe(log);
- setName(Name);
- setPhone(Phone);
- setAddress(Address);
- }
- });
+ useEffect(() => {
+ if (New || !data) return;
+
+ const { Name, Phone, Address } = data;
+
+ setName(Name);
+ setPhone(Phone);
+ setAddress(Address);
+ }, [data]);
const { dispatch, dispatchToast } = useErrorToast(log);
diff --git a/src/Components/ShopCart/Confirm.tsx b/src/Components/ShopCart/Confirm.tsx
index c2e714e..640dfa3 100644
--- a/src/Components/ShopCart/Confirm.tsx
+++ b/src/Components/ShopCart/Confirm.tsx
@@ -8,7 +8,7 @@ import { Logger } from "~/Helpers/Logger";
import { ColFlex } from "~/Helpers/Styles";
import { useErrorToast } from "~/Helpers/useToast";
import { Hub } from "~/ShopNet";
-import { DelegateDataGrid } from "../DataGrid/Delegate";
+import { DelegateDataGrid } from "../DataGrid";
import { useRouter } from "../Router";
import { CartColumns } from "./Columns";
import { useShopCart } from "./Context";
diff --git a/src/Components/ShopCart/Persona.tsx b/src/Components/ShopCart/Persona.tsx
index 2088768..31a925e 100644
--- a/src/Components/ShopCart/Persona.tsx
+++ b/src/Components/ShopCart/Persona.tsx
@@ -38,7 +38,7 @@ export interface IPersona {
export function PersonaInfo({ Log }: { Log: Logger }) {
const style = useStyles();
const log = useConst(() => Log.With("PersonaInfo"));
- const { data } = Hub.User.Get.useMe(log);
+ const data = Hub.User.Get.useMe(log);
return <>
diff --git a/src/Components/ShopCart/index.tsx b/src/Components/ShopCart/index.tsx
index c8388f7..2aeb232 100644
--- a/src/Components/ShopCart/index.tsx
+++ b/src/Components/ShopCart/index.tsx
@@ -4,7 +4,7 @@ import { CartRegular } from "@fluentui/react-icons";
import { useBoolean, useUpdateEffect } from "ahooks";
import { Logger } from "~/Helpers/Logger";
import { Flex } from "~/Helpers/Styles";
-import { DelegateDataGrid } from "../DataGrid/Delegate";
+import { DelegateDataGrid } from "../DataGrid";
import { CartColumns } from "./Columns";
import { Confirm } from "./Confirm";
import { useShopCart } from "./Context";
diff --git a/src/Components/TopNavBar.tsx b/src/Components/TopNavBar.tsx
index 5e3154b..f5838d5 100644
--- a/src/Components/TopNavBar.tsx
+++ b/src/Components/TopNavBar.tsx
@@ -12,7 +12,7 @@ import { ShopCart } from "./ShopCart";
* @since 0.1.0 MusiLand
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
navBox: {
position: "fixed",
top: 0,
@@ -44,10 +44,10 @@ const useStyle = makeStyles({
/**
* @author Aloento
* @since 0.1.0 MusiLand
- * @version 0.1.1
+ * @version 0.1.2
*/
export function TopNavBar() {
- const style = useStyle();
+ const style = useStyles();
return (
diff --git a/src/Helpers/CoverCol.tsx b/src/Helpers/CoverCol.tsx
index 2095680..e62164e 100644
--- a/src/Helpers/CoverCol.tsx
+++ b/src/Helpers/CoverCol.tsx
@@ -8,7 +8,7 @@ import { Cover } from "./Styles";
* @since 0.1.0
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
unset: {
flexBasis: "unset",
flexGrow: 0
@@ -32,7 +32,7 @@ export function MakeCoverCol(size: number, log: Logger) {
return createTableColumn<{ Cover: string; }>({
columnId: "Cover",
renderHeaderCell: () => {
- const style = useStyle();
+ const style = useStyles();
return (
@@ -41,7 +41,7 @@ export function MakeCoverCol(size: number, log: Logger) {
)
},
renderCell(item) {
- const style = useStyle();
+ const style = useStyles();
return (
diff --git a/src/Lexical/Editor.tsx b/src/Lexical/Editor.tsx
index a3125f4..dfbe599 100644
--- a/src/Lexical/Editor.tsx
+++ b/src/Lexical/Editor.tsx
@@ -26,12 +26,12 @@ import { MarkdownShortcutPlugin } from "./Plugins/MarkdownShortcutPlugin";
import { TabFocusPlugin } from "./Plugins/TabFocusPlugin";
import { TablePlugin } from "./Plugins/TablePlugin";
import { ToolbarPlugin } from "./Plugins/ToolbarPlugin";
-import { useLexEditorTheme } from "./Themes/LexEditorTheme";
+import { useLexEditorTheme } from "./Theme";
import { LexContentEditable } from "./UI/ContentEditable";
import { Placeholder } from "./UI/Placeholder";
import { SetCurrentEditor } from "./Utils";
-const useStyle = makeStyles({
+const useStyles = makeStyles({
shell: {
lineHeight: "1.7"
},
@@ -78,7 +78,7 @@ export function LexEditor(): JSX.Element {
const placeholder =
const [anchor, setAnchor] = useState();
- const style = useStyle();
+ const style = useStyles();
return (
diff --git a/src/Lexical/Lazy.tsx b/src/Lexical/Lazy.tsx
new file mode 100644
index 0000000..c46a302
--- /dev/null
+++ b/src/Lexical/Lazy.tsx
@@ -0,0 +1,18 @@
+import { Spinner } from "@fluentui/react-components";
+import { lazy, Suspense } from "react";
+import type { ILexical } from "./Context/Setting";
+
+/**
+ * @author Aloento
+ * @since 1.2.0
+ * @version 0.1.0
+ */
+export function Lexical(props: ILexical) {
+ return (
+
}>
+
+
+ );
+}
+
+const Wrapper = lazy(() => import("./"));
diff --git a/src/Lexical/Nodes/Table/Component.tsx b/src/Lexical/Nodes/Table/Component.tsx
index 8fd0532..c0c75b2 100644
--- a/src/Lexical/Nodes/Table/Component.tsx
+++ b/src/Lexical/Nodes/Table/Component.tsx
@@ -1334,7 +1334,7 @@ function TableComponent({ nodeKey, rows: rawRows, theme, }: ITableComponent): JS
if (!cellEditor)
return null;
- const style = useStyle();
+ const style = useStyles();
return (
@@ -1387,7 +1387,7 @@ function TableComponent({ nodeKey, rows: rawRows, theme, }: ITableComponent): JS
);
}
-const useStyle = makeStyles({
+const useStyles = makeStyles({
box: { position: "relative" }
});
diff --git a/src/Lexical/Nodes/Table/TableCell.tsx b/src/Lexical/Nodes/Table/TableCell.tsx
index 5db8771..3a28504 100644
--- a/src/Lexical/Nodes/Table/TableCell.tsx
+++ b/src/Lexical/Nodes/Table/TableCell.tsx
@@ -78,7 +78,7 @@ export function TableCell({
setShowMenu(false);
}, [isEditing, isPrimarySelected]);
- const style = useStyle();
+ const style = useStyles();
return (
editor.isEditable());
const [isEditorEmpty, setIsEditorEmpty] = useState(true);
diff --git a/src/Lexical/Plugins/AutoLinkPlugin/index.tsx b/src/Lexical/Plugins/AutoLinkPlugin.tsx
similarity index 100%
rename from src/Lexical/Plugins/AutoLinkPlugin/index.tsx
rename to src/Lexical/Plugins/AutoLinkPlugin.tsx
diff --git a/src/Lexical/Plugins/ClickableLinkPlugin/index.ts b/src/Lexical/Plugins/ClickableLinkPlugin.ts
similarity index 100%
rename from src/Lexical/Plugins/ClickableLinkPlugin/index.ts
rename to src/Lexical/Plugins/ClickableLinkPlugin.ts
diff --git a/src/Lexical/Plugins/CodeActionMenuPlugin/CopyButton.tsx b/src/Lexical/Plugins/CodeActionMenuPlugin/CopyButton.tsx
index c0248a0..047572b 100644
--- a/src/Lexical/Plugins/CodeActionMenuPlugin/CopyButton.tsx
+++ b/src/Lexical/Plugins/CodeActionMenuPlugin/CopyButton.tsx
@@ -5,7 +5,7 @@ import { useDebounceFn } from "ahooks";
import { $getNearestNodeFromDOMNode, $getSelection, $setSelection, LexicalEditor } from "lexical";
import { useState } from "react";
-const useStyle = makeStyles({
+const useStyles = makeStyles({
green: {
color: tokens.colorPaletteLightGreenForeground3
}
@@ -50,7 +50,7 @@ export function CopyButton({ editor, getCodeDOMNode }: ICopyButton) {
}
}
- const style = useStyle();
+ const style = useStyles();
return : } />;
diff --git a/src/Lexical/Plugins/CodeActionMenuPlugin/index.tsx b/src/Lexical/Plugins/CodeActionMenuPlugin/index.tsx
index d13cb37..9c4424b 100644
--- a/src/Lexical/Plugins/CodeActionMenuPlugin/index.tsx
+++ b/src/Lexical/Plugins/CodeActionMenuPlugin/index.tsx
@@ -13,7 +13,7 @@ interface Position {
right: string;
}
-const useStyle = makeStyles({
+const useStyles = makeStyles({
container: {
height: "35.8px",
fontSize: "10px",
@@ -131,7 +131,7 @@ export function CodeActionMenuPlugin({ anchor = document.body }: { anchor?: HTML
});
const codeFriendlyName = getLanguageFriendlyName(lang);
- const style = useStyle();
+ const style = useStyles();
return (
diff --git a/src/Lexical/Plugins/CodeHighlightPlugin/index.ts b/src/Lexical/Plugins/CodeHighlightPlugin.ts
similarity index 100%
rename from src/Lexical/Plugins/CodeHighlightPlugin/index.ts
rename to src/Lexical/Plugins/CodeHighlightPlugin.ts
diff --git a/src/Lexical/Plugins/DraggableBlockPlugin/index.tsx b/src/Lexical/Plugins/DraggableBlockPlugin.tsx
similarity index 98%
rename from src/Lexical/Plugins/DraggableBlockPlugin/index.tsx
rename to src/Lexical/Plugins/DraggableBlockPlugin.tsx
index 54aaee7..0df2209 100644
--- a/src/Lexical/Plugins/DraggableBlockPlugin/index.tsx
+++ b/src/Lexical/Plugins/DraggableBlockPlugin.tsx
@@ -18,9 +18,9 @@ import {
useRef,
useState
} from "react";
-import { isHTMLElement } from "../../Utils/guard";
-import { Point } from "../../Utils/point";
-import { Rect } from "../../Utils/rect";
+import { isHTMLElement } from "../Utils/guard";
+import { Point } from "../Utils/point";
+import { Rect } from "../Utils/rect";
let prevIndex = Infinity;
@@ -298,7 +298,7 @@ function DraggableBlockMenu({ editor, anchor }: { editor: LexicalEditor; anchor:
hideTargetLine(targetLineRef.current);
}
- const style = useStyle();
+ const style = useStyles();
return (
@@ -316,7 +316,7 @@ function DraggableBlockMenu({ editor, anchor }: { editor: LexicalEditor; anchor:
);
}
-const useStyle = makeStyles({
+const useStyles = makeStyles({
meun: {
...shorthands.borderRadius("4px"),
...shorthands.padding("2px", "1px"),
diff --git a/src/Lexical/Plugins/FloatingLinkEditorPlugin/index.tsx b/src/Lexical/Plugins/FloatingLinkEditorPlugin.tsx
similarity index 96%
rename from src/Lexical/Plugins/FloatingLinkEditorPlugin/index.tsx
rename to src/Lexical/Plugins/FloatingLinkEditorPlugin.tsx
index e178565..1743aa5 100644
--- a/src/Lexical/Plugins/FloatingLinkEditorPlugin/index.tsx
+++ b/src/Lexical/Plugins/FloatingLinkEditorPlugin.tsx
@@ -18,9 +18,9 @@ import {
} from "lexical";
import { Dispatch, useCallback, useEffect, useRef, useState } from "react";
import { BaseCard, Col, Flex } from "~/Helpers/Styles";
-import { getSelectedNode } from "../../Utils/getSelectedNode";
-import { setFloatingElemPosition } from "../../Utils/setFloatingElemPosition";
-import { sanitizeUrl } from "../../Utils/url";
+import { getSelectedNode } from "../Utils/getSelectedNode";
+import { setFloatingElemPosition } from "../Utils/setFloatingElemPosition";
+import { sanitizeUrl } from "../Utils/url";
interface IFloatingLinkEditor {
editor: LexicalEditor;
@@ -150,7 +150,7 @@ function FloatingLinkEditor({ editor, isLink, setIsLink, anchor }: IFloatingLink
inputRef.current.focus();
}, [isEditMode]);
- const style = useStyle();
+ const style = useStyles();
return (
@@ -195,7 +195,7 @@ const box = {
...shorthands.padding("4px", "12px"),
}
-const useStyle = makeStyles({
+const useStyles = makeStyles({
editor: {
...BaseCard,
...Col,
diff --git a/src/Lexical/Plugins/FloatingTextFormatToolbarPlugin/index.tsx b/src/Lexical/Plugins/FloatingTextFormatToolbarPlugin.tsx
similarity index 97%
rename from src/Lexical/Plugins/FloatingTextFormatToolbarPlugin/index.tsx
rename to src/Lexical/Plugins/FloatingTextFormatToolbarPlugin.tsx
index b8d8f3c..3c0db8a 100644
--- a/src/Lexical/Plugins/FloatingTextFormatToolbarPlugin/index.tsx
+++ b/src/Lexical/Plugins/FloatingTextFormatToolbarPlugin.tsx
@@ -18,9 +18,9 @@ import {
} from "lexical";
import { useCallback, useEffect, useRef, useState } from "react";
import { BaseCard } from "~/Helpers/Styles";
-import { getDOMRangeRect } from "../../Utils/getDOMRangeRect";
-import { getSelectedNode } from "../../Utils/getSelectedNode";
-import { setFloatingElemPosition } from "../../Utils/setFloatingElemPosition";
+import { getDOMRangeRect } from "../Utils/getDOMRangeRect";
+import { getSelectedNode } from "../Utils/getSelectedNode";
+import { setFloatingElemPosition } from "../Utils/setFloatingElemPosition";
interface ITextFormatFloatingToolbar {
editor: LexicalEditor;
@@ -126,7 +126,7 @@ function TextFormatFloatingToolbar({
isLink && "link"
] as string[];
- const style = useStyle();
+ const style = useStyles();
return (
;
diff --git a/src/Lexical/Plugins/LinkPlugin/index.tsx b/src/Lexical/Plugins/LinkPlugin.tsx
similarity index 80%
rename from src/Lexical/Plugins/LinkPlugin/index.tsx
rename to src/Lexical/Plugins/LinkPlugin.tsx
index dc181bf..f040ed3 100644
--- a/src/Lexical/Plugins/LinkPlugin/index.tsx
+++ b/src/Lexical/Plugins/LinkPlugin.tsx
@@ -1,5 +1,5 @@
import { LinkPlugin as LexicalLinkPlugin } from "@lexical/react/LexicalLinkPlugin";
-import { validateUrl } from "../../Utils/url";
+import { validateUrl } from "../Utils/url";
export function LinkPlugin(): JSX.Element {
return ;
diff --git a/src/Lexical/Plugins/ListMaxIndentLevelPlugin/index.ts b/src/Lexical/Plugins/ListMaxIndentLevelPlugin.ts
similarity index 100%
rename from src/Lexical/Plugins/ListMaxIndentLevelPlugin/index.ts
rename to src/Lexical/Plugins/ListMaxIndentLevelPlugin.ts
diff --git a/src/Lexical/Plugins/TabFocusPlugin/index.tsx b/src/Lexical/Plugins/TabFocusPlugin.tsx
similarity index 100%
rename from src/Lexical/Plugins/TabFocusPlugin/index.tsx
rename to src/Lexical/Plugins/TabFocusPlugin.tsx
diff --git a/src/Lexical/Plugins/TablePlugin/index.tsx b/src/Lexical/Plugins/TablePlugin.tsx
similarity index 97%
rename from src/Lexical/Plugins/TablePlugin/index.tsx
rename to src/Lexical/Plugins/TablePlugin.tsx
index 6500794..fd69fe1 100644
--- a/src/Lexical/Plugins/TablePlugin/index.tsx
+++ b/src/Lexical/Plugins/TablePlugin.tsx
@@ -16,8 +16,8 @@ import {
createCommand
} from "lexical";
import { createContext, useContext, useEffect, useMemo, useState } from "react";
-import { IRow, TableNode, createCell, createRow } from "../../Nodes/Table";
-import { invariant } from "../../Utils/invariant";
+import { IRow, TableNode, createCell, createRow } from "../Nodes/Table";
+import { invariant } from "../Utils/invariant";
export type InsertTableCommandPayload = Readonly<{
columns: string | number;
diff --git a/src/Lexical/Plugins/ToolbarPlugin/Font.tsx b/src/Lexical/Plugins/ToolbarPlugin/Font.tsx
index 87dd7ab..af813f0 100644
--- a/src/Lexical/Plugins/ToolbarPlugin/Font.tsx
+++ b/src/Lexical/Plugins/ToolbarPlugin/Font.tsx
@@ -64,7 +64,7 @@ export function FontDropDown({ editor, value, style, disabled = false }: IFontDr
{(style === "font-family" ? FONT_FAMILY_OPTIONS : FONT_SIZE_OPTIONS).map(
- ([option, text]) =>
diff --git a/src/Lexical/Plugins/ToolbarPlugin/index.tsx b/src/Lexical/Plugins/ToolbarPlugin/index.tsx
index da33e25..33ea350 100644
--- a/src/Lexical/Plugins/ToolbarPlugin/index.tsx
+++ b/src/Lexical/Plugins/ToolbarPlugin/index.tsx
@@ -53,7 +53,7 @@ import { BlockFormat, BlockTypeToBlockName } from "./BlockFormat";
import { LexColorPicker } from "./ColorPopover";
import { FontDropDown } from "./Font";
-const useStyle = makeStyles({
+const useStyles = makeStyles({
box: {
columnGap: "1px",
backgroundColor: "#fff",
@@ -250,7 +250,7 @@ export function ToolbarPlugin(): JSX.Element {
[activeEditor, selectedElementKey]
);
- const style = useStyle();
+ const style = useStyles();
return (
- {CODE_LANGUAGE_OPTIONS.map(([value, name]) =>
- onCodeLanguageSelect(value)} children={name} />)}
+ {CODE_LANGUAGE_OPTIONS.map(([value, name], i) =>
+ onCodeLanguageSelect(value)} children={name} />)}
diff --git a/src/Lexical/Themes/LexEditorTheme.ts b/src/Lexical/Theme.ts
similarity index 98%
rename from src/Lexical/Themes/LexEditorTheme.ts
rename to src/Lexical/Theme.ts
index a28ba9c..80e6966 100644
--- a/src/Lexical/Themes/LexEditorTheme.ts
+++ b/src/Lexical/Theme.ts
@@ -1,7 +1,7 @@
import { makeStyles, mergeClasses, shorthands } from "@fluentui/react-components";
import type { EditorThemeClasses } from "lexical";
-const useStyle = makeStyles({
+const useStyles = makeStyles({
ltr: { textAlign: "left" },
rtl: { textAlign: "right" },
paragraph: {
@@ -258,7 +258,7 @@ const useStyle = makeStyles({
marginLeft: "16px",
listStylePosition: "inside"
},
- listItem: { ...shorthands.margin(0, "32px") },
+ listItem: { ...shorthands.margin(0, "8px") },
tokenComment: { color: "slategray" },
tokenPunctuation: { color: "#999" },
tokenProperty: { color: "#905" },
@@ -274,7 +274,7 @@ const useStyle = makeStyles({
});
export function useLexEditorTheme(): EditorThemeClasses {
- const style = useStyle();
+ const style = useStyles();
return {
blockCursor: "LexEditor_blockCursor",
code: mergeClasses(style.code, "LexEditor_code"),
diff --git a/src/Lexical/UI/ContentEditable.tsx b/src/Lexical/UI/ContentEditable.tsx
index 2621a20..dbe62b3 100644
--- a/src/Lexical/UI/ContentEditable.tsx
+++ b/src/Lexical/UI/ContentEditable.tsx
@@ -2,7 +2,7 @@ import { makeStyles, mergeClasses, shorthands } from "@fluentui/react-components
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { useLexical } from "../Context/Setting";
-const useStyle = makeStyles({
+const useStyles = makeStyles({
root: {
...shorthands.border(0),
fontSize: "15px",
@@ -35,7 +35,7 @@ const useStyle = makeStyles({
});
export function LexContentEditable({ className, table }: { className?: string, table?: true }): JSX.Element {
- const style = useStyle();
+ const style = useStyles();
const { Display } = useLexical();
return
@@ -306,7 +306,7 @@ export function ImageResizer({
);
}
-const useStyle = makeStyles({
+const useStyles = makeStyles({
button: {
minWidth: "unset",
fontWeight: "unset",
diff --git a/src/Lexical/UI/Placeholder.tsx b/src/Lexical/UI/Placeholder.tsx
index bb1d6d6..0c7d329 100644
--- a/src/Lexical/UI/Placeholder.tsx
+++ b/src/Lexical/UI/Placeholder.tsx
@@ -1,7 +1,7 @@
import { makeStyles, shorthands } from "@fluentui/react-components";
import { ReactNode } from "react";
-const useStyle = makeStyles({
+const useStyles = makeStyles({
box: {
fontSize: "15px",
color: "#999",
@@ -19,6 +19,6 @@ const useStyle = makeStyles({
});
export function Placeholder({ children, className }: { children: ReactNode; className?: string; }): JSX.Element {
- const style = useStyle();
+ const style = useStyles();
return {children}
;
}
diff --git a/src/Lexical/index.tsx b/src/Lexical/index.tsx
index 146464e..0df6e6e 100644
--- a/src/Lexical/index.tsx
+++ b/src/Lexical/index.tsx
@@ -6,7 +6,7 @@ import { LexicalContext, type ILexical } from "./Context/Setting";
import { LexEditor } from "./Editor";
import { LexicalNodes } from "./Nodes/LexicalNodes";
import { TableContext } from "./Plugins/TablePlugin";
-import { useLexEditorTheme } from "./Themes/LexEditorTheme";
+import { useLexEditorTheme } from "./Theme";
/**
* Lexical Editor
@@ -15,7 +15,7 @@ import { useLexEditorTheme } from "./Themes/LexEditorTheme";
* @since MusiLand 0.5.0
* @version 0.1.0
*/
-export function Lexical({
+function Lexical({
Namespace = Dic.Name,
Plugin = LexRichTextPreset,
Editable = true,
@@ -51,3 +51,6 @@ export function Lexical({
);
}
+
+/** @deprecated */
+export default Lexical;
diff --git a/src/Pages/Admin/Nav.tsx b/src/Pages/Admin/Nav.tsx
index 410849b..c73a0fe 100644
--- a/src/Pages/Admin/Nav.tsx
+++ b/src/Pages/Admin/Nav.tsx
@@ -7,7 +7,7 @@ import { Flex } from "~/Helpers/Styles";
* @since 0.1.0
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
box: {
...Flex,
flexGrow: 1,
@@ -29,7 +29,7 @@ const useStyle = makeStyles({
* @version 0.1.1
*/
export function AdminTopNav() {
- const style = useStyle();
+ const style = useStyles();
const { Paths } = useRouter();
const path1 = Paths.at(0);
const path2 = Paths.at(1) || "Product";
diff --git a/src/Pages/Admin/Order/List.tsx b/src/Pages/Admin/Order/List.tsx
index f9d2ccc..17f6303 100644
--- a/src/Pages/Admin/Order/List.tsx
+++ b/src/Pages/Admin/Order/List.tsx
@@ -1,5 +1,5 @@
import { DataGridCell, DataGridHeaderCell, TableColumnDefinition, createTableColumn, makeStyles } from "@fluentui/react-components";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { ICartItem } from "~/Components/ShopCart";
/**
@@ -64,6 +64,6 @@ const columns: TableColumnDefinition[] = [
*/
export function AdminOrderList({ Items }: { Items?: ICartItem[] }) {
return (
-
+
)
}
diff --git a/src/Pages/Admin/Order/index.tsx b/src/Pages/Admin/Order/index.tsx
index 3f37bb3..f12195a 100644
--- a/src/Pages/Admin/Order/index.tsx
+++ b/src/Pages/Admin/Order/index.tsx
@@ -1,6 +1,6 @@
import { DataGridCell, DataGridHeaderCell, TableColumnDefinition, createTableColumn, makeStyles } from "@fluentui/react-components";
import { useRequest } from "ahooks";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { IOrderItem } from "~/Pages/History";
import { HistoryColumns } from "~/Pages/History/Columns";
@@ -93,6 +93,6 @@ export function AdminOrder() {
});
return (
-
+
)
}
diff --git a/src/Pages/Admin/Product/Add.tsx b/src/Pages/Admin/Product/Add.tsx
index a0f6a3d..a14802a 100644
--- a/src/Pages/Admin/Product/Add.tsx
+++ b/src/Pages/Admin/Product/Add.tsx
@@ -21,7 +21,7 @@ const log = new Logger("Admin", "Product", "AddButton");
/**
* @author Aloento
* @since 0.1.0
- * @version 0.3.2
+ * @version 0.3.3
*/
export function AdminProductAddButton() {
const { Nav, Paths } = useRouter();
@@ -33,7 +33,7 @@ export function AdminProductAddButton() {
const { dispatch, dispatchToast } = useErrorToast(log);
- const { run } = AdminHub.Product.Post.useCreate({
+ const { run, loading } = AdminHub.Product.Post.useCreate({
manual: true,
onError(e, params) {
dispatch({
@@ -52,6 +52,7 @@ export function AdminProductAddButton() {
);
Nav("Admin", data);
+ setName("");
}
});
@@ -82,7 +83,13 @@ export function AdminProductAddButton() {
-
+
diff --git a/src/Pages/Admin/Product/Combo/Detail.tsx b/src/Pages/Admin/Product/Combo/Detail.tsx
index a161812..1e8dd09 100644
--- a/src/Pages/Admin/Product/Combo/Detail.tsx
+++ b/src/Pages/Admin/Product/Combo/Detail.tsx
@@ -3,7 +3,7 @@ import { DismissRegular, EditRegular } from "@fluentui/react-icons";
import { useBoolean, useRequest } from "ahooks";
import { isInteger } from "lodash-es";
import { useState } from "react";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { Flex } from "~/Helpers/Styles";
import { useErrorToast } from "~/Helpers/useToast";
@@ -152,7 +152,7 @@ export function AdminProductComboDetail({ Id, ProdId, Combo, Stock, Refresh }: I
setCombo({ ...combo });
},
...x
- })) || []}
+ }))}
Columns={columns}
/>
diff --git a/src/Pages/Admin/Product/Combo/New.tsx b/src/Pages/Admin/Product/Combo/New.tsx
index 98748ec..7bc621b 100644
--- a/src/Pages/Admin/Product/Combo/New.tsx
+++ b/src/Pages/Admin/Product/Combo/New.tsx
@@ -3,7 +3,7 @@ import { AddRegular, DismissRegular } from "@fluentui/react-icons";
import { useBoolean, useRequest } from "ahooks";
import { isInteger } from "lodash-es";
import { useState } from "react";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { Flex } from "~/Helpers/Styles";
import { useErrorToast } from "~/Helpers/useToast";
@@ -140,7 +140,7 @@ export function AdminProductNewCombo({ ProdId, Refresh }: { ProdId: number; Refr
setCombo({ ...combo });
},
...x
- })) || []}
+ }))}
Columns={columns}
/>
diff --git a/src/Pages/Admin/Product/Combo/index.tsx b/src/Pages/Admin/Product/Combo/index.tsx
index 842f3e2..3bb31f0 100644
--- a/src/Pages/Admin/Product/Combo/index.tsx
+++ b/src/Pages/Admin/Product/Combo/index.tsx
@@ -1,6 +1,6 @@
import { DataGridCell, DataGridHeaderCell, Subtitle1, TableColumnDefinition, createTableColumn, makeStyles } from "@fluentui/react-components";
import { useRequest } from "ahooks";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { Flex } from "~/Helpers/Styles";
import { Hub } from "~/ShopNet";
@@ -132,7 +132,7 @@ export function AdminProductCombo({ ProdId }: { ProdId: number }) {
({ ProdId, Refresh: run, ...x })) || []}
+ Items={data?.map(x => ({ ProdId, Refresh: run, ...x }))}
Columns={columns}
/>
>
diff --git a/src/Pages/Admin/Product/Delete.tsx b/src/Pages/Admin/Product/Delete.tsx
index 3bd0d75..4db95fb 100644
--- a/src/Pages/Admin/Product/Delete.tsx
+++ b/src/Pages/Admin/Product/Delete.tsx
@@ -1,21 +1,29 @@
-import { Button, Toast, ToastTitle } from "@fluentui/react-components";
+import { Button, Popover, PopoverSurface, PopoverTrigger, Toast, ToastTitle, makeStyles, tokens } from "@fluentui/react-components";
import { useRouter } from "~/Components/Router";
import { Logger } from "~/Helpers/Logger";
+import { ColFlex } from "~/Helpers/Styles";
import { useErrorToast } from "~/Helpers/useToast";
import { AdminHub } from "~/ShopNet/Admin";
const log = new Logger("Admin", "Product", "Detail", "Delete");
+const useStyles = makeStyles({
+ root: {
+ ...ColFlex,
+ rowGap: tokens.spacingHorizontalS
+ }
+});
+
/**
* @author Aloento
* @since 1.0.0
- * @version 0.1.1
+ * @version 0.2.1
*/
export function AdminProductDelete({ ProdId }: { ProdId: number }) {
const { Nav } = useRouter();
const { dispatch, dispatchToast } = useErrorToast(log);
- const { run } = AdminHub.Product.Delete.useProduct({
+ const { run, loading } = AdminHub.Product.Delete.useProduct({
manual: true,
onError(e, params) {
dispatch({
@@ -33,13 +41,30 @@ export function AdminProductDelete({ ProdId }: { ProdId: number }) {
);
Nav("/Admin");
- location.reload();
}
});
+ const style = useStyles();
+
return (
-
+
+
+
+
+
+
+ Are You Sure?
+
+
+
+
)
}
diff --git a/src/Pages/Admin/Product/Detail.tsx b/src/Pages/Admin/Product/Detail.tsx
index 0677010..92c7c2a 100644
--- a/src/Pages/Admin/Product/Detail.tsx
+++ b/src/Pages/Admin/Product/Detail.tsx
@@ -8,6 +8,7 @@ import { ColFlex } from "~/Helpers/Styles";
import { AdminProductCategory } from "./Category";
import { AdminProductCombo } from "./Combo";
import { AdminProductDelete } from "./Delete";
+import { AdminProductLexical } from "./Lexical";
import { AdminProductName } from "./Name";
import { AdminProductPhoto } from "./Photo";
import { AdminProductVariant } from "./Variant";
@@ -28,16 +29,19 @@ const useStyles = makeStyles({
/**
* @author Aloento
* @since 0.1.0
- * @version 0.2.1
+ * @version 0.2.2
*/
export function AdminProductDetail({ ProdId }: { ProdId: number }) {
const style = useStyles();
- const [open, { toggle, setTrue }] = useBoolean();
+ const [open, { setFalse, setTrue }] = useBoolean();
const { Nav, Paths } = useRouter();
+ const id = parseInt(Paths.at(1)!);
useEffect(() => {
- if (parseInt(Paths.at(1)!) === ProdId)
+ if (id === ProdId)
setTrue();
+ else
+ setFalse();
}, [Paths]);
return <>
@@ -52,7 +56,6 @@ export function AdminProductDetail({ ProdId }: { ProdId: number }) {
}
onClick={() => {
Nav("Admin");
- toggle();
+ setFalse();
}}
/>}
>
@@ -80,8 +83,7 @@ export function AdminProductDetail({ ProdId }: { ProdId: number }) {
- Rich Text Editor is temporarily unavailable.
-
+
diff --git a/src/Pages/Admin/Product/Lexical.tsx b/src/Pages/Admin/Product/Lexical.tsx
new file mode 100644
index 0000000..7763dc6
--- /dev/null
+++ b/src/Pages/Admin/Product/Lexical.tsx
@@ -0,0 +1,102 @@
+import { Button, Toast, ToastTitle, makeStyles, tokens } from "@fluentui/react-components";
+import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from "@fluentui/react-components/unstable";
+import { useBoolean, useRequest } from "ahooks";
+import { Logger } from "~/Helpers/Logger";
+import { Flex } from "~/Helpers/Styles";
+import { useErrorToast } from "~/Helpers/useToast";
+import { Lexical } from "~/Lexical/Lazy";
+import { Hub } from "~/ShopNet";
+import { AdminHub } from "~/ShopNet/Admin";
+
+/**
+ * @author Aloento
+ * @since 1.2.0
+ * @version 0.1.0
+ */
+const useStyles = makeStyles({
+ btn: {
+ ...Flex,
+ columnGap: tokens.spacingVerticalS
+ },
+ drawer: {
+ width: "1100px"
+ }
+});
+
+const log = new Logger("Admin", "Product", "Lexical");
+
+/**
+ * @author Aloento
+ * @since 1.2.0
+ * @version 0.2.0
+ */
+export function AdminProductLexical({ ProdId }: { ProdId: number }) {
+ const style = useStyles();
+ const [open, { toggle, setTrue }] = useBoolean();
+
+ const { data, run: update } = useRequest(() => Hub.Product.Get.Lexical(ProdId));
+
+ const { dispatch, dispatchToast } = useErrorToast(log);
+
+ const { run } = AdminHub.Product.Post.useLexical({
+ manual: true,
+ onError(e, req) {
+ dispatch({
+ Message: "Failed Update Description",
+ Request: req,
+ Error: e
+ });
+ },
+ onSuccess() {
+ dispatchToast(
+
+ Description Updated
+ ,
+ { intent: "success" }
+ );
+
+ update();
+ toggle();
+ },
+ });
+
+ return <>
+
+
+
+
+
+
+
+
+
+
+
+ }>
+ Edit Product Description
+
+
+
+
+
+
+
+ >
+}
diff --git a/src/Pages/Admin/Product/Photo/Edit.tsx b/src/Pages/Admin/Product/Photo/Edit.tsx
index d7f1c0f..edc877c 100644
--- a/src/Pages/Admin/Product/Photo/Edit.tsx
+++ b/src/Pages/Admin/Product/Photo/Edit.tsx
@@ -1,6 +1,7 @@
-import { Button, Dialog, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Field, Image, Input, Toast, ToastTitle, makeStyles, tokens } from "@fluentui/react-components";
+import { Button, Dialog, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Field, Input, Toast, ToastTitle, makeStyles, tokens } from "@fluentui/react-components";
import { DismissRegular, EditRegular } from "@fluentui/react-icons";
import { useState } from "react";
+import { GuidImage } from "~/Helpers/GuidImage";
import { Logger } from "~/Helpers/Logger";
import { ColFlex, Cover, Flex } from "~/Helpers/Styles";
import { useErrorToast } from "~/Helpers/useToast";
@@ -44,7 +45,7 @@ const log = new Logger("Admin", "Product", "Detail", "Photo", "Edit");
/**
* @author Aloento
* @since 0.5.0
- * @version 0.3.2
+ * @version 0.3.3
*/
export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }: IAdminProductPhotoEdit) {
const style = useStyles();
@@ -135,10 +136,11 @@ export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }
-
diff --git a/src/Pages/Admin/Product/Photo/index.tsx b/src/Pages/Admin/Product/Photo/index.tsx
index b62911d..62c09f7 100644
--- a/src/Pages/Admin/Product/Photo/index.tsx
+++ b/src/Pages/Admin/Product/Photo/index.tsx
@@ -1,7 +1,8 @@
import { Button, DataGridCell, DataGridHeaderCell, Subtitle1, TableColumnDefinition, Toast, ToastTitle, createTableColumn, makeStyles } from "@fluentui/react-components";
import { AddRegular, ArrowDownRegular, ArrowUpRegular } from "@fluentui/react-icons";
import { useRequest } from "ahooks";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { useState } from "react";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { MakeCoverCol } from "~/Helpers/CoverCol";
import { Logger } from "~/Helpers/Logger";
import { Flex } from "~/Helpers/Styles";
@@ -111,11 +112,22 @@ let refreshCarousel: () => void;
/**
* @author Aloento
* @since 0.5.0
- * @version 0.3.2
+ * @version 0.4.0
*/
export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
- const { data, run } = useRequest(() => Hub.Product.Get.Carousel(ProdId, log), {
- onError: log.error
+ const [list, setList] = useState([]);
+
+ const { run } = useRequest(() => Hub.Product.Get.PhotoList(ProdId, log), {
+ onError: log.error,
+ onSuccess([raw]) {
+ const map = raw.map(x => ({
+ Id: x.Order,
+ Cover: x.ObjectId,
+ Caption: x.Caption || "No Caption"
+ }));
+
+ setList(map);
+ }
});
refreshCarousel = run;
@@ -138,7 +150,7 @@ export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
{ intent: "success" }
);
- refreshCarousel();
+ run();
}
});
@@ -165,6 +177,6 @@ export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
-
+
>
}
diff --git a/src/Pages/Admin/Product/Row.tsx b/src/Pages/Admin/Product/Row.tsx
new file mode 100644
index 0000000..9c18e0c
--- /dev/null
+++ b/src/Pages/Admin/Product/Row.tsx
@@ -0,0 +1,69 @@
+import { DataGridRow, TableRowData } from "@fluentui/react-components";
+import { useAsyncEffect, useBoolean } from "ahooks";
+import { useState } from "react";
+import { Logger } from "~/Helpers/Logger";
+import { Hub } from "~/ShopNet";
+import { AdminHub } from "~/ShopNet/Admin";
+import { IProductItem } from ".";
+
+const log = new Logger("Admin", "Product", "Row");
+
+/**
+ * @author Aloento
+ * @since 1.3.0
+ * @version 0.1.0
+ */
+export function AdminProductRow({ item: id }: TableRowData) {
+ const [detail, setDetail] = useState(() => ({
+ Id: id,
+ Cover: "",
+ Name: "Loading..."
+ }));
+
+ const [block, { setTrue }] = useBoolean();
+
+ const hub = Hub.Product.Get;
+
+ useAsyncEffect(async () => {
+ const prod = await hub.Product(id).catch(log.error);
+
+ if (!prod) {
+ log.warn(`Product ${id} Not Found`);
+ return setTrue();
+ }
+
+ let item = {
+ ...detail,
+ Name: prod.Name,
+ Category: prod.Category || "Pending"
+ };
+
+ setDetail(item);
+
+ const [_, cover] = await hub.PhotoList(id, log);
+
+ if (!cover)
+ log.warn(`Product ${id} has no photo`);
+
+ setDetail(item = {
+ ...item,
+ Cover: cover
+ });
+
+ const count = await AdminHub.Product.Get.Count(id).catch(log.error);
+
+ count && setDetail({
+ ...item,
+ ...count
+ });
+ }, []);
+
+ if (block)
+ return null;
+
+ return (
+ key={id}>
+ {({ renderCell }) => renderCell(detail)}
+
+ );
+}
diff --git a/src/Pages/Admin/Product/Variant/Edit/index.tsx b/src/Pages/Admin/Product/Variant/Edit/index.tsx
index 305f661..10352d2 100644
--- a/src/Pages/Admin/Product/Variant/Edit/index.tsx
+++ b/src/Pages/Admin/Product/Variant/Edit/index.tsx
@@ -1,6 +1,6 @@
import { Button, DataGridCell, DataGridHeaderCell, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, TableColumnDefinition, createTableColumn, makeStyles, tokens } from "@fluentui/react-components";
import { DismissRegular, EditRegular } from "@fluentui/react-icons";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { ColFlex } from "~/Helpers/Styles";
import { IVariantItem } from "..";
import { AdminProductTypeDelete } from "./Delete";
diff --git a/src/Pages/Admin/Product/Variant/index.tsx b/src/Pages/Admin/Product/Variant/index.tsx
index 0c1dd0e..37edcaf 100644
--- a/src/Pages/Admin/Product/Variant/index.tsx
+++ b/src/Pages/Admin/Product/Variant/index.tsx
@@ -1,6 +1,6 @@
import { DataGridCell, DataGridHeaderCell, Subtitle1, TableColumnDefinition, createTableColumn, makeStyles } from "@fluentui/react-components";
import { useRequest } from "ahooks";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { Flex } from "~/Helpers/Styles";
import { AdminHub } from "~/ShopNet/Admin";
@@ -149,6 +149,6 @@ export function AdminProductVariant({ ProdId }: { ProdId: number }) {
-
+
>
}
diff --git a/src/Pages/Admin/Product/index.tsx b/src/Pages/Admin/Product/index.tsx
index bca346f..a3b8308 100644
--- a/src/Pages/Admin/Product/index.tsx
+++ b/src/Pages/Admin/Product/index.tsx
@@ -1,21 +1,28 @@
-import { Body1Strong, DataGridCell, DataGridHeaderCell, TableColumnDefinition, createTableColumn, makeStyles } from "@fluentui/react-components";
-import { useRequest } from "ahooks";
+import { Body1Strong, DataGrid, DataGridBody, DataGridCell, DataGridHeader, DataGridHeaderCell, DataGridRow, SkeletonItem, TableColumnDefinition, createTableColumn, makeStyles } from "@fluentui/react-components";
import { MakeCoverCol } from "~/Helpers/CoverCol";
import { Logger } from "~/Helpers/Logger";
import { AdminHub } from "~/ShopNet/Admin";
-import { DelegateDataGrid } from "../../../Components/DataGrid/Delegate";
import { AdminProductDetail } from "./Detail";
+import { AdminProductRow } from "./Row";
/**
* @author Aloento
* @since 0.1.0
- * @version 0.1.0
+ * @version 0.2.0
*/
-export interface IProductItem {
+export interface IProductItem extends Partial {
Id: number;
Cover: string;
Name: string;
- Category: string;
+ Category?: string;
+}
+
+/**
+ * @author Aloento
+ * @since 1.3.0
+ * @version 0.1.0
+ */
+export interface IProductCount {
Variant: number;
Combo: number;
Stock: number;
@@ -43,15 +50,13 @@ const log = new Logger("Admin", "Product");
/**
* @author Aloento
* @since 0.1.0
- * @version 0.1.1
+ * @version 0.2.0
*/
const columns: TableColumnDefinition[] = [
MakeCoverCol(50, log),
- createTableColumn({
+ createTableColumn({
columnId: "Product",
- renderHeaderCell: () => {
- return Product
- },
+ renderHeaderCell: () => Product,
renderCell(item) {
return (
@@ -60,11 +65,9 @@ const columns: TableColumnDefinition[] = [
)
}
}),
- createTableColumn({
+ createTableColumn({
columnId: "Category",
- renderHeaderCell: () => {
- return Category
- },
+ renderHeaderCell: () => Category,
renderCell(item) {
return (
@@ -73,42 +76,34 @@ const columns: TableColumnDefinition[] = [
)
}
}),
- createTableColumn({
+ createTableColumn({
columnId: "Variant",
- renderHeaderCell: () => {
- return Variant
- },
+ renderHeaderCell: () => Variant,
renderCell(item) {
return {item.Variant}
}
}),
- createTableColumn({
+ createTableColumn({
columnId: "Combo",
- renderHeaderCell: () => {
- return Combo
- },
+ renderHeaderCell: () => Combo,
renderCell(item) {
return {item.Combo}
}
}),
- createTableColumn({
+ createTableColumn({
columnId: "Stock",
- renderHeaderCell: () => {
- return Stock
- },
+ renderHeaderCell: () => Stock,
renderCell(item) {
return {item.Stock}
}
}),
- createTableColumn({
+ createTableColumn({
columnId: "Action",
- renderHeaderCell: () => {
- return (
-
- Detail
-
- )
- },
+ renderHeaderCell: () => (
+
+ Detail
+
+ ),
renderCell(item) {
return (
@@ -122,14 +117,27 @@ const columns: TableColumnDefinition[] = [
/**
* @author Aloento
* @since 0.1.0
- * @version 0.1.1
+ * @version 2.0.0
*/
export function AdminProduct() {
- const { data } = useRequest(() => AdminHub.Product.Get.List(log), {
- onError: log.error
- });
+ const idList = AdminHub.Product.Get.useList(log);
return (
-
+
+
+
+ {({ renderHeaderCell }) => renderHeaderCell()}
+
+
+
+ >
+ {(data) => }
+
+
+ {!idList && }
+
)
}
diff --git a/src/Pages/Admin/User/index.tsx b/src/Pages/Admin/User/index.tsx
index 6a81c95..7c8f144 100644
--- a/src/Pages/Admin/User/index.tsx
+++ b/src/Pages/Admin/User/index.tsx
@@ -1,6 +1,6 @@
-import { TableColumnDefinition, createTableColumn } from "@fluentui/react-components";
+import { DataGridCell, DataGridHeaderCell, TableColumnDefinition, createTableColumn } from "@fluentui/react-components";
import { useRequest } from "ahooks";
-import { DefaultDataGrid } from "~/Components/DataGrid";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { AdminHub } from "~/ShopNet/Admin";
import { AdminUserDelete } from "./Delete";
@@ -23,55 +23,49 @@ const log = new Logger("Admin", "User");
/**
* @author Aloento
* @since 0.1.0
- * @version 0.2.0
+ * @version 0.3.0
*/
const columns: TableColumnDefinition[] = [
createTableColumn({
columnId: "Id",
- renderHeaderCell: () => {
- return "Id";
- },
+ renderHeaderCell: () => "Id",
renderCell(item) {
return item.Id;
}
}),
createTableColumn({
columnId: "Name",
- renderHeaderCell: () => {
- return "Real Name";
- },
+ renderHeaderCell: () => "Real Name",
renderCell(item) {
return item.Name;
}
}),
createTableColumn({
columnId: "Email",
- renderHeaderCell: () => {
- return "E-Mail";
- },
+ renderHeaderCell: () => "E-Mail",
renderCell(item) {
return item.EMail;
}
}),
createTableColumn({
columnId: "Admin",
- renderHeaderCell: () => {
- return "Admin";
- },
+ renderHeaderCell: () => "Admin",
renderCell(item) {
return
},
}),
createTableColumn({
columnId: "Delete",
- renderHeaderCell: () => {
- return "Delete";
- },
+ renderHeaderCell: () => "Delete",
renderCell(item) {
return
},
})
-]
+].map(({ renderHeaderCell, renderCell, ...col }) => ({
+ ...col,
+ renderHeaderCell: () => {renderHeaderCell()},
+ renderCell: (item) => {renderCell(item)}
+}))
/**
* @author Aloento
@@ -83,7 +77,7 @@ let refreshUser: () => void;
/**
* @author Aloento
* @since 0.1.0
- * @version 0.2.1
+ * @version 0.2.2
*/
export function AdminUser() {
const { data, run } = useRequest(() => AdminHub.User.Get.List(), {
@@ -92,6 +86,6 @@ export function AdminUser() {
refreshUser = run;
return (
-
+
)
}
diff --git a/src/Pages/Admin/index.tsx b/src/Pages/Admin/index.tsx
index b9703d0..233e3b6 100644
--- a/src/Pages/Admin/index.tsx
+++ b/src/Pages/Admin/index.tsx
@@ -31,13 +31,13 @@ function Admin() {
}
}, [path]);
- const { data, loading } = Hub.User.Get.useMe(log);
+ const data = Hub.User.Get.useMe(log);
- if (loading)
+ if (!data)
return ;
- if (!data?.Admin)
- return Nav("/");
+ if (!data.Admin)
+ return Nav("/")!;
return content;
}
diff --git a/src/Pages/Gallery/index.tsx b/src/Pages/Gallery/index.tsx
index bdebd11..09df756 100644
--- a/src/Pages/Gallery/index.tsx
+++ b/src/Pages/Gallery/index.tsx
@@ -24,7 +24,7 @@ const useStyles = makeStyles({
* @since 0.1.0
* @version 0.1.0
*/
-export interface IProductInfo {
+export interface IGallery {
Cover: string;
Name: string;
}
diff --git a/src/Pages/History/Detail.tsx b/src/Pages/History/Detail.tsx
index 2c27825..545e557 100644
--- a/src/Pages/History/Detail.tsx
+++ b/src/Pages/History/Detail.tsx
@@ -4,7 +4,7 @@ import { useConst } from "@fluentui/react-hooks";
import { DismissRegular, OpenRegular } from "@fluentui/react-icons";
import { useBoolean, useRequest } from "ahooks";
import { useEffect } from "react";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { OrderInfo } from "~/Components/OrderInfo";
import { useRouter } from "~/Components/Router";
import { ICartItem } from "~/Components/ShopCart";
@@ -160,7 +160,7 @@ export function OrderDetail({ OrderId, ParentLog }: { OrderId: number } & ICompL
diff --git a/src/Pages/History/index.tsx b/src/Pages/History/index.tsx
index 6a19c73..7af6384 100644
--- a/src/Pages/History/index.tsx
+++ b/src/Pages/History/index.tsx
@@ -1,6 +1,6 @@
import { useConst } from "@fluentui/react-hooks";
import { useRequest } from "ahooks";
-import { DelegateDataGrid } from "~/Components/DataGrid/Delegate";
+import { DelegateDataGrid } from "~/Components/DataGrid";
import { Logger } from "~/Helpers/Logger";
import { Hub } from "~/ShopNet";
import { HistoryColumns } from "./Columns";
@@ -32,7 +32,7 @@ function History() {
});
return (
- HistoryColumns(log))} />
+ HistoryColumns(log))} />
)
}
diff --git a/src/Pages/Product/Carousel.tsx b/src/Pages/Product/Carousel.tsx
index 5012102..fe451d4 100644
--- a/src/Pages/Product/Carousel.tsx
+++ b/src/Pages/Product/Carousel.tsx
@@ -12,7 +12,7 @@ import { Hub } from "~/ShopNet";
* @since 0.1.0
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
img: {
aspectRatio: "1",
...Cover,
@@ -30,22 +30,21 @@ const log = new Logger("Product", "Carousel");
* @version 0.3.0
*/
export function ProductCarousel({ Id }: { Id: number; }) {
- const style = useStyle();
+ const style = useStyles();
const [imgs, setImgs] = useState<[string, string?][]>([[img]]);
- useRequest(() => Hub.Product.Get.Carousel(Id, log), {
- async onSuccess(data) {
- setImgs(Array<[string, string?]>(data.length).fill([img]));
+ useRequest(() => Hub.Product.Get.PhotoList(Id, log), {
+ async onSuccess([list]) {
+ setImgs(Array<[string, string?]>(list.length).fill([img]));
- for (let i = 0; i < data.length; i++) {
- Hub.Storage.GetBySlice(data[i].Cover, log).then(slice => {
+ for (let i = 0; i < list.length; i++)
+ Hub.Storage.GetBySlice(list[i].ObjectId, log).then(slice => {
setImgs(x => {
const n = [...x];
- n[i] = [URL.createObjectURL(new Blob(slice)), data[i].Caption];
+ n[i] = [URL.createObjectURL(new Blob(slice)), list[i].Caption];
return n;
});
});
- }
},
onError: log.error
});
diff --git a/src/Pages/Product/Context.tsx b/src/Pages/Product/Context.tsx
index 8721f9b..abb1d8e 100644
--- a/src/Pages/Product/Context.tsx
+++ b/src/Pages/Product/Context.tsx
@@ -1,5 +1,5 @@
import { isEqual } from "lodash-es";
-import { createContext, useContext, useEffect, useState } from "react";
+import { createContext, useContext, useState } from "react";
import { IComboItem } from "../Admin/Product/Combo";
/**
@@ -35,23 +35,17 @@ export function useRadioGroup() {
/**
* @author Aloento
* @since 0.5.0
- * @version 0.3.0
+ * @version 0.3.1
*/
export function RadioGroupContext({ children }: { children: React.ReactNode }) {
const [curr, setCurr] = useState({});
- const [combo, setCombo] = useState();
const [all, setAll] = useState([]);
- useEffect(() => {
- const combo = all.find(x => isEqual(x.Combo, curr));
- setCombo(combo);
- }, [curr, all]);
-
return (
isEqual(x.Combo, curr)),
SetAll: setAll
}}>
{children}
diff --git a/src/Pages/Product/Lexical.tsx b/src/Pages/Product/Lexical.tsx
index def3984..0db1835 100644
--- a/src/Pages/Product/Lexical.tsx
+++ b/src/Pages/Product/Lexical.tsx
@@ -1,34 +1,40 @@
import { makeStyles, shorthands, tokens } from "@fluentui/react-components";
import { useRequest } from "ahooks";
-import { BaseCard } from "~/Helpers/Styles";
-import { Lexical } from "~/Lexical";
+import { BaseCard, ColFlex } from "~/Helpers/Styles";
+import { Lexical } from "~/Lexical/Lazy";
import { Hub } from "~/ShopNet";
/**
* @author Aloento
* @since 0.5.0
- * @version 0.1.0
+ * @version 0.1.1
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
lex: {
...BaseCard,
...shorthands.padding(tokens.spacingHorizontalXL)
+ },
+ skel: {
+ ...ColFlex,
+ rowGap: tokens.spacingVerticalM
}
})
/**
* @author Aloento
* @since 0.5.0
- * @version 0.1.0
+ * @version 0.2.0
*/
export function ProductLexicalRender({ ProdId }: { ProdId: number }) {
- const style = useStyle();
-
+ const style = useStyles();
const { data, loading } = useRequest(() => Hub.Product.Get.Lexical(ProdId));
+ if (loading || !data)
+ return null;
+
return (
- {loading ? "Loading..." : }
+
)
}
diff --git a/src/Pages/Product/Quantity.tsx b/src/Pages/Product/Quantity.tsx
index 7b6bd15..e7f9df6 100644
--- a/src/Pages/Product/Quantity.tsx
+++ b/src/Pages/Product/Quantity.tsx
@@ -10,7 +10,7 @@ import { useRadioGroup } from "./Context";
* @since 1.2.0
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
fore: {
color: tokens.colorBrandForeground1
},
@@ -35,7 +35,7 @@ const useStyle = makeStyles({
* @version 0.2.0
*/
export function ProductQuantity({ Id }: { Id: number; }) {
- const style = useStyle();
+ const style = useStyles();
const { Combo } = useRadioGroup();
const [_, max] = useLimit(Id);
diff --git a/src/Pages/Product/RadioGroup.tsx b/src/Pages/Product/RadioGroup.tsx
index 26d8ac0..607d217 100644
--- a/src/Pages/Product/RadioGroup.tsx
+++ b/src/Pages/Product/RadioGroup.tsx
@@ -7,7 +7,7 @@ import { useRadioGroup } from "./Context";
* @since 0.1.0
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
fore: {
color: tokens.colorBrandForeground1,
textTransform: "uppercase"
@@ -41,7 +41,7 @@ interface IProductRadioGroup {
* @version 0.2.2
*/
export function ProductRadioGroup({ Variant, Types }: IProductRadioGroup) {
- const style = useStyle();
+ const style = useStyles();
const { Current, Update } = useRadioGroup();
return (
diff --git a/src/Pages/Product/index.tsx b/src/Pages/Product/index.tsx
index 11b94b1..c2a1b2e 100644
--- a/src/Pages/Product/index.tsx
+++ b/src/Pages/Product/index.tsx
@@ -9,6 +9,7 @@ import { Hub } from "~/ShopNet";
import { IComboItem } from "../Admin/Product/Combo";
import { ProductCarousel } from "./Carousel";
import { RadioGroupContext } from "./Context";
+import { ProductLexicalRender } from "./Lexical";
import { ProductQuantity } from "./Quantity";
import { ProductRadioList } from "./RadioList";
@@ -17,7 +18,7 @@ import { ProductRadioList } from "./RadioList";
* @since 0.1.0
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
main: ColFlex,
info: {
...Flex,
@@ -26,15 +27,18 @@ const useStyle = makeStyles({
detail: {
...BaseCard,
...Col,
- height: "fit-content",
- flexBasis: "50%",
- flexShrink: 0,
rowGap: tokens.spacingVerticalXL,
paddingTop: tokens.spacingVerticalM,
paddingLeft: tokens.spacingHorizontalXXL,
paddingRight: tokens.spacingHorizontalXXL,
paddingBottom: tokens.spacingHorizontalXXL
},
+ lex: {
+ ...ColFlex,
+ flexBasis: "50%",
+ flexShrink: 0,
+ rowGap: tokens.spacingVerticalXL,
+ },
fore: {
color: tokens.colorBrandForeground1
}
@@ -55,10 +59,10 @@ const log = new Logger("Product");
/**
* @author Aloento
* @since 0.1.0
- * @version 0.2.0
+ * @version 0.3.0
*/
function Product() {
- const style = useStyle();
+ const style = useStyles();
const { Nav, Paths } = useRouter();
const id = parseInt(Paths.at(1)!);
@@ -82,22 +86,24 @@ function Product() {
-
-
- {data?.Name || "Loading..."}
-
+
+
+
+ {data?.Name || "Loading..."}
+
-
+
-
+
-
+
-
+
+
+
+
-
- {/*
*/}
)
diff --git a/src/Pages/index.tsx b/src/Pages/index.tsx
index 518fa3b..a7e463f 100644
--- a/src/Pages/index.tsx
+++ b/src/Pages/index.tsx
@@ -12,7 +12,7 @@ import { NotFound } from "./404";
* @since 0.2.2 MusiLand
* @version 0.1.0
*/
-const useStyle = makeStyles({
+const useStyles = makeStyles({
body: {
...ColFlex,
minWidth: "1024px",
@@ -41,7 +41,7 @@ const useStyle = makeStyles({
* @version 0.4.0
*/
export function Layout() {
- const style = useStyle();
+ const style = useStyles();
const { Paths } = useRouter();
const path = Paths.at(0);
diff --git a/src/ShopNet/Admin/AdminNet.ts b/src/ShopNet/Admin/AdminNet.ts
index 175e1d0..d4aaab8 100644
--- a/src/ShopNet/Admin/AdminNet.ts
+++ b/src/ShopNet/Admin/AdminNet.ts
@@ -1,13 +1,12 @@
import { HttpTransportType, HubConnectionBuilder, LogLevel } from "@microsoft/signalr";
import { MessagePackHubProtocol } from "@microsoft/signalr-protocol-msgpack";
-import { Dayjs } from "dayjs";
-import { Common, IConcurrency } from "../Database";
+import { Common } from "../Database";
import { SignalR } from "../SignalR";
/**
* @author Aloento
* @since 1.0.0
- * @version 0.1.1
+ * @version 0.1.2
*/
export abstract class AdminNet extends SignalR {
/** "|", "AdminNet" */
@@ -40,23 +39,10 @@ export abstract class AdminNet extends SignalR {
/**
* @author Aloento
- * @since 1.0.0
- * @version 0.1.0
- */
- protected static override WithVersionCache(
- key: string | number, methodName: string
- ): Promise {
- return super.WithVersionCache(key, methodName, true);
- }
-
- /**
- * @author Aloento
- * @since 1.0.0
+ * @since 1.3.0
* @version 0.1.0
*/
- protected static override WithTimeCache(
- key: string | number, methodName: string, exp: Dayjs, ...args: any[]
- ): Promise {
- return super.WithTimeCache(`Admin_${key}`, methodName, exp, ...args);
+ public static override Index(key: string | number, methodName: string): string {
+ return `${methodName}_Admin_${key}`;
}
}
diff --git a/src/ShopNet/Admin/Order/Entity.ts b/src/ShopNet/Admin/Order/Entity.ts
index e87a447..2c2c5c1 100644
--- a/src/ShopNet/Admin/Order/Entity.ts
+++ b/src/ShopNet/Admin/Order/Entity.ts
@@ -19,7 +19,7 @@ export abstract class AdminOrderEntity extends AdminNet {
TrackingNumber?: string;
} & IConcurrency) | void> {
this.EnsureLogin();
- return this.WithVersionCache(key, "OrderEntity");
+ return this.GetVersionCache(key, "OrderEntity");
}
/**
@@ -33,6 +33,6 @@ export abstract class AdminOrderEntity extends AdminNet {
CreateAt: Date;
} & IConcurrency) | void> {
this.EnsureLogin();
- return this.WithVersionCache(key, "CommentEntity");
+ return this.GetVersionCache(key, "CommentEntity");
}
}
diff --git a/src/ShopNet/Admin/Order/Get.ts b/src/ShopNet/Admin/Order/Get.ts
index 6c5c579..20252f4 100644
--- a/src/ShopNet/Admin/Order/Get.ts
+++ b/src/ShopNet/Admin/Order/Get.ts
@@ -1,10 +1,9 @@
-import dayjs from "dayjs";
import { ICartItem } from "~/Components/ShopCart";
import { Logger } from "~/Helpers/Logger";
import { IAdminOrderItem } from "~/Pages/Admin/Order";
import { IComment } from "~/Pages/History/Comment";
import { IOrderDetail } from "~/Pages/History/Detail";
-import { ProductEntity } from "~/ShopNet/Product/Entity";
+import { ProductData } from "~/ShopNet/Product/Data";
import { ProductGet } from "~/ShopNet/Product/Get";
import { AdminNet } from "../AdminNet";
import { AdminUserEntity } from "../User/Entity";
@@ -28,13 +27,13 @@ export abstract class AdminOrderGet extends AdminNet {
this.EnsureLogin();
const log = pLog.With(...this.Log, "List");
- const list = await this.WithTimeCache<
+ const list = await this.GetTimeCache<
{
OrderId: number;
Products: number[];
Quantity: number;
}[]
- >("", "OrderGetList", dayjs().add(1, "m"));
+ >("", "OrderGetList", (x) => x.add(1, "m"));
const items: IAdminOrderItem[] = [];
@@ -49,7 +48,7 @@ export abstract class AdminOrderGet extends AdminNet {
const prodNames: string[] = [];
for (const prodId of meta.Products) {
- const prod = await ProductEntity.Product(prodId);
+ const prod = await ProductData.Product(prodId);
if (!prod) {
log.warn(`[Mismatch] Product ${prodId} not found`);
@@ -89,7 +88,7 @@ export abstract class AdminOrderGet extends AdminNet {
this.EnsureLogin();
const log = pLog.With(...this.Log, "Detail");
- const meta = await this.WithTimeCache<
+ const meta = await this.GetTimeCache<
{
Items: {
Types: number[];
@@ -97,7 +96,7 @@ export abstract class AdminOrderGet extends AdminNet {
}[],
Comments: number[];
}
- >(orderId, "OrderGetDetail", dayjs().add(1, "m"), orderId);
+ >(orderId, "OrderGetDetail", (x) => x.add(1, "m"), orderId);
const items: ICartItem[] = [];
let index = 0;
@@ -107,14 +106,14 @@ export abstract class AdminOrderGet extends AdminNet {
let prodId = 0;
for (const typeId of combo.Types) {
- const type = await ProductEntity.Type(typeId);
+ const type = await ProductData.Type(typeId);
if (!type) {
log.warn(`[Mismatch] Type ${typeId} not found. Order : ${orderId}`);
continue;
}
- const vari = await ProductEntity.Variant(type.VariantId);
+ const vari = await ProductData.Variant(type.VariantId);
if (!vari) {
log.warn(`[Mismatch] Variant ${type.VariantId} not found. Type : ${typeId}, Order : ${orderId}`);
@@ -125,15 +124,14 @@ export abstract class AdminOrderGet extends AdminNet {
prodId = vari.ProductId;
}
- const prod = await ProductEntity.Product(prodId);
+ const prod = await ProductData.Product(prodId);
if (!prod) {
log.warn(`[Mismatch] Product ${prodId} not found. Order : ${orderId}`);
continue;
}
- const list = await ProductGet.PhotoList(prodId);
- const cover = await this.FindCover(list, prodId, log);
+ const [_, cover] = await ProductGet.PhotoList(prodId, log);
if (!cover)
log.warn(`Product ${prodId} has no photo`);
diff --git a/src/ShopNet/Admin/Product/Delete.ts b/src/ShopNet/Admin/Product/Delete.ts
index 39da2ed..046598e 100644
--- a/src/ShopNet/Admin/Product/Delete.ts
+++ b/src/ShopNet/Admin/Product/Delete.ts
@@ -1,5 +1,6 @@
import { useRequest } from "ahooks";
import { Options } from "ahooks/lib/useRequest/src/types";
+import dayjs from "dayjs";
import { AdminNet } from "../AdminNet";
/**
@@ -63,12 +64,14 @@ export abstract class AdminProductDelete extends AdminNet {
/**
* @author Aloento
* @since 1.0.0
- * @version 0.2.0
+ * @version 0.2.1
*/
public static useProduct(options: Options) {
return useRequest(async prodId => {
const res = await this.Invoke("ProductDeleteProduct", prodId);
this.EnsureTrue(res);
+
+ this.UpdateCache(x => x.filter(x => x !== prodId), "", "ProductGetList", dayjs().add(1, "m"));
return res;
}, options);
}
diff --git a/src/ShopNet/Admin/Product/Get.ts b/src/ShopNet/Admin/Product/Get.ts
index 485a683..c74b4b3 100644
--- a/src/ShopNet/Admin/Product/Get.ts
+++ b/src/ShopNet/Admin/Product/Get.ts
@@ -1,8 +1,8 @@
-import dayjs from "dayjs";
+import { useConst } from "@fluentui/react-hooks";
+import { useLiveQuery } from "dexie-react-hooks";
import type { Logger } from "~/Helpers/Logger";
-import { IProductItem } from "~/Pages/Admin/Product";
+import { IProductCount } from "~/Pages/Admin/Product";
import { IVariantItem } from "~/Pages/Admin/Product/Variant";
-import { ProductEntity } from "~/ShopNet/Product/Entity";
import { ProductGet } from "~/ShopNet/Product/Get";
import { AdminNet } from "../AdminNet";
@@ -18,48 +18,26 @@ export abstract class AdminProductGet extends AdminNet {
/**
* @author Aloento
* @since 0.5.0
- * @version 1.0.1
+ * @version 3.0.0
*/
- public static async List(pLog: Logger): Promise {
- const log = pLog.With(...this.Log, "List");
-
- const list = await this.WithTimeCache<
- {
- ProductId: number;
- Variant: number;
- Combo: number;
- Stock: number;
- }[]
- >("", "ProductGetList", dayjs().add(1, "m"));
-
- const items: IProductItem[] = [];
-
- for (const meta of list) {
- const prod = await ProductEntity.Product(meta.ProductId);
-
- if (!prod) {
- log.warn(`Product ${meta.ProductId} Not Found`);
- continue;
- }
+ public static useList(pLog: Logger): number[] | void {
+ const log = useConst(() => pLog.With(...this.Log, "List"));
- const photos = await ProductGet.PhotoList(meta.ProductId);
- const cover = await this.FindCover(photos, meta.ProductId, log);
+ const res = useLiveQuery(() =>
+ this.GetTimeCache("", "ProductGetList", (x) => x.add(1, "m"))
+ .catch(log.error)
+ );
- if (!cover)
- log.warn(`Product ${meta.ProductId} has no photo`);
-
- items.push({
- Id: meta.ProductId,
- Cover: cover || "",
- Name: prod.Name,
- Category: prod.Category || "Pending",
- Variant: meta.Variant,
- Combo: meta.Combo,
- Stock: meta.Stock
- });
- }
+ return res;
+ }
- return items;
+ /**
+ * @author Aloento
+ * @since 1.3.0
+ * @version 0.1.0
+ */
+ public static Count(prodId: number): Promise {
+ return this.GetTimeCache(prodId, "ProductGetCount", (x) => x.add(1, "m"), prodId);
}
/**
@@ -68,7 +46,7 @@ export abstract class AdminProductGet extends AdminNet {
* @version 1.0.0
*/
public static async Name(prodId: number): Promise {
- const prod = await ProductEntity.Product(prodId);
+ const prod = await ProductGet.Product(prodId);
if (!prod)
throw new Error(`Product ${prodId} Not Found`);
@@ -82,7 +60,7 @@ export abstract class AdminProductGet extends AdminNet {
* @version 1.0.0
*/
public static async Category(prodId: number): Promise {
- const prod = await ProductEntity.Product(prodId);
+ const prod = await ProductGet.Product(prodId);
if (!prod)
throw new Error(`Product ${prodId} Not Found`);
@@ -98,17 +76,17 @@ export abstract class AdminProductGet extends AdminNet {
public static async Variants(prodId: number, pLog: Logger): Promise {
const log = pLog.With(...this.Log, "Variants");
- const list = await this.WithTimeCache<
+ const list = await this.GetTimeCache<
{
VariantId: number;
Types: number[];
}[]
- >(prodId, "ProductGetVariants", dayjs().add(1, "m"), prodId);
+ >(prodId, "ProductGetVariants", (x) => x.add(1, "m"), prodId);
const items: IVariantItem[] = [];
for (const meta of list) {
- const vari = await ProductEntity.Variant(meta.VariantId);
+ const vari = await ProductGet.Variant(meta.VariantId);
if (!vari) {
log.warn(`Variant ${meta} Not Found. Product : ${prodId}`);
@@ -118,7 +96,7 @@ export abstract class AdminProductGet extends AdminNet {
const types: string[] = [];
for (const typeId of meta.Types) {
- const type = await ProductEntity.Type(typeId);
+ const type = await ProductGet.Type(typeId);
if (!type) {
log.warn(`Type ${typeId} Not Found. Variant : ${meta.VariantId}, Product : ${prodId}`);
diff --git a/src/ShopNet/Admin/Product/Post.ts b/src/ShopNet/Admin/Product/Post.ts
index 4b84d3b..70b4b43 100644
--- a/src/ShopNet/Admin/Product/Post.ts
+++ b/src/ShopNet/Admin/Product/Post.ts
@@ -1,8 +1,10 @@
import { useConst } from "@fluentui/react-hooks";
import { useRequest } from "ahooks";
import { Options } from "ahooks/lib/useRequest/src/types";
+import dayjs from "dayjs";
import { Subject } from "rxjs";
import { Logger } from "~/Helpers/Logger";
+import { CurrentEditor } from "~/Lexical/Utils";
import { AdminNet } from "../AdminNet";
/**
@@ -17,10 +19,14 @@ export abstract class AdminProductPost extends AdminNet {
/**
* @author Aloento
* @since 0.5.0
- * @version 0.2.0
+ * @version 0.4.0
*/
public static useCreate(options: Options) {
- return useRequest(name => this.Invoke("ProductPostCreate", name), options);
+ return useRequest(async name => {
+ const res = await this.Invoke("ProductPostCreate", name);
+ this.UpdateCache(x => [res, ...x], "", "ProductGetList", dayjs().add(1, "m"))
+ return res;
+ }, options);
}
/**
@@ -86,4 +92,23 @@ export abstract class AdminProductPost extends AdminNet {
public static useCombo(options: Options, number]>) {
return useRequest((prodId, combo, stock) => this.Invoke("ProductPostCombo", prodId, combo, stock), options);
}
+
+ /**
+ * @author Aloento
+ * @since 1.2.0
+ * @version 0.1.0
+ */
+ public static useLexical(options: Options) {
+ return useRequest(async prodId => {
+ const state = CurrentEditor?.getEditorState();
+ let json: string | undefined;
+
+ if (state && !state.isEmpty())
+ json = JSON.stringify(state.toJSON());
+
+ const res = await this.Invoke("ProductPostDescription", prodId, json);
+ this.EnsureTrue(res);
+ return res;
+ }, options);
+ }
}
diff --git a/src/ShopNet/Admin/User/Entity.ts b/src/ShopNet/Admin/User/Entity.ts
index f8f0a08..8981a61 100644
--- a/src/ShopNet/Admin/User/Entity.ts
+++ b/src/ShopNet/Admin/User/Entity.ts
@@ -20,6 +20,6 @@ export abstract class AdminUserEntity extends AdminNet {
Admin?: boolean;
} & IConcurrency) | void> {
this.EnsureLogin();
- return this.WithVersionCache(key, "UserEntity");
+ return this.GetVersionCache(key, "UserEntity");
}
}
diff --git a/src/ShopNet/Admin/User/Get.ts b/src/ShopNet/Admin/User/Get.ts
index e18a761..04ac1ae 100644
--- a/src/ShopNet/Admin/User/Get.ts
+++ b/src/ShopNet/Admin/User/Get.ts
@@ -1,4 +1,3 @@
-import dayjs from "dayjs";
import { IPersona } from "~/Components/ShopCart/Persona";
import { IUserItem } from "~/Pages/Admin/User";
import { AdminNet } from "../AdminNet";
@@ -36,7 +35,7 @@ export abstract class AdminUserGet extends AdminNet {
* @version 1.0.0
*/
public static async List(): Promise {
- const list = await this.WithTimeCache("", "UserGetList", dayjs().add(1, "m"));
+ const list = await this.GetTimeCache("", "UserGetList", (x) => x.add(1, "m"));
const res: IUserItem[] = [];
for (const userId of list) {
diff --git a/src/ShopNet/Gallery/Get.ts b/src/ShopNet/Gallery/Get.ts
index 7885e4a..e4ba8c2 100644
--- a/src/ShopNet/Gallery/Get.ts
+++ b/src/ShopNet/Gallery/Get.ts
@@ -1,4 +1,3 @@
-import dayjs from "dayjs";
import { ShopNet } from "../ShopNet";
/**
@@ -13,7 +12,7 @@ export abstract class GalleryGet extends ShopNet {
* @version 0.2.1
*/
public static Categories(): Promise {
- return this.WithTimeCache("", "GalleryGetCategories", dayjs().add(1, "m"));
+ return this.GetTimeCache("", "GalleryGetCategories", (x) => x.add(1, "m"));
}
/**
@@ -22,7 +21,7 @@ export abstract class GalleryGet extends ShopNet {
* @version 0.2.1
*/
public static async Products(category: string): Promise<[number[], number]> {
- const nums = await this.WithTimeCache(category, "GalleryGetProducts", dayjs().add(1, "m"), category);
+ const nums = await this.GetTimeCache(category, "GalleryGetProducts", (x) => x.add(1, "m"), category);
return [
nums,
diff --git a/src/ShopNet/Order/Entity.ts b/src/ShopNet/Order/Entity.ts
index e542a62..fb104fa 100644
--- a/src/ShopNet/Order/Entity.ts
+++ b/src/ShopNet/Order/Entity.ts
@@ -18,7 +18,7 @@ export abstract class OrderEntity extends ShopNet {
TrackingNumber?: string;
} & IConcurrency) | void> {
this.EnsureLogin();
- return this.WithVersionCache(key, "OrderEntity");
+ return this.GetVersionCache(key, "OrderEntity");
}
/**
@@ -32,6 +32,6 @@ export abstract class OrderEntity extends ShopNet {
CreateAt: Date;
} & IConcurrency) | void> {
this.EnsureLogin();
- return this.WithVersionCache(key, "CommentEntity");
+ return this.GetVersionCache(key, "CommentEntity");
}
}
diff --git a/src/ShopNet/Order/Get.ts b/src/ShopNet/Order/Get.ts
index 6dcb890..1d0fd36 100644
--- a/src/ShopNet/Order/Get.ts
+++ b/src/ShopNet/Order/Get.ts
@@ -1,10 +1,9 @@
-import dayjs from "dayjs";
import { ICartItem } from "~/Components/ShopCart";
import { Logger } from "~/Helpers/Logger";
import { IOrderItem } from "~/Pages/History";
import { IComment } from "~/Pages/History/Comment";
import { IOrderDetail } from "~/Pages/History/Detail";
-import { ProductEntity } from "../Product/Entity";
+import { ProductData } from "../Product/Data";
import { ProductGet } from "../Product/Get";
import { ShopNet } from "../ShopNet";
import { OrderEntity } from "./Entity";
@@ -27,13 +26,13 @@ export abstract class OrderGet extends ShopNet {
this.EnsureLogin();
const log = pLog.With(...this.Log, "List");
- const list = await this.WithTimeCache<
+ const list = await this.GetTimeCache<
{
OrderId: number;
Products: number[];
Quantity: number;
}[]
- >("", "OrderGetList", dayjs().add(1, "m"));
+ >("", "OrderGetList", (x) => x.add(1, "m"));
const items: IOrderItem[] = [];
@@ -48,7 +47,7 @@ export abstract class OrderGet extends ShopNet {
const prodNames: string[] = [];
for (const prodId of meta.Products) {
- const prod = await ProductEntity.Product(prodId);
+ const prod = await ProductData.Product(prodId);
if (!prod) {
log.warn(`[Mismatch] Product ${prodId} not found`);
@@ -80,7 +79,7 @@ export abstract class OrderGet extends ShopNet {
this.EnsureLogin();
const log = pLog.With(...this.Log, "Detail");
- const meta = await this.WithTimeCache<
+ const meta = await this.GetTimeCache<
{
Items: {
Types: number[];
@@ -88,7 +87,7 @@ export abstract class OrderGet extends ShopNet {
}[],
Comments: number[];
}
- >(orderId, "OrderGetDetail", dayjs().add(1, "m"), orderId);
+ >(orderId, "OrderGetDetail", (x) => x.add(1, "m"), orderId);
const items: ICartItem[] = [];
let index = 0;
@@ -98,14 +97,14 @@ export abstract class OrderGet extends ShopNet {
let prodId = 0;
for (const typeId of combo.Types) {
- const type = await ProductEntity.Type(typeId);
+ const type = await ProductData.Type(typeId);
if (!type) {
log.warn(`[Mismatch] Type ${typeId} not found. Order : ${orderId}`);
continue;
}
- const vari = await ProductEntity.Variant(type.VariantId);
+ const vari = await ProductData.Variant(type.VariantId);
if (!vari) {
log.warn(`[Mismatch] Variant ${type.VariantId} not found. Type : ${typeId}, Order : ${orderId}`);
@@ -116,15 +115,14 @@ export abstract class OrderGet extends ShopNet {
prodId = vari.ProductId;
}
- const prod = await ProductEntity.Product(prodId);
+ const prod = await ProductData.Product(prodId);
if (!prod) {
log.warn(`[Mismatch] Product ${prodId} not found. Order : ${orderId}`);
continue;
}
- const list = await ProductGet.PhotoList(prodId);
- const cover = await this.FindCover(list, prodId, log);
+ const [_, cover] = await ProductGet.PhotoList(prodId, log);
if (!cover)
log.warn(`Product ${prodId} has no photo`);
diff --git a/src/ShopNet/Product/Data.ts b/src/ShopNet/Product/Data.ts
new file mode 100644
index 0000000..996dec0
--- /dev/null
+++ b/src/ShopNet/Product/Data.ts
@@ -0,0 +1,75 @@
+import { IConcurrency } from "../Database";
+import { ShopNet } from "../ShopNet";
+
+/**
+ * @author Aloento
+ * @since 1.0.0
+ * @version 0.1.0
+ */
+export abstract class ProductData extends ShopNet {
+ /**
+ * @author Aloento
+ * @since 1.0.0
+ * @version 0.1.0
+ * @liveSafe
+ */
+ public static Product(key: number): Promise<{
+ Name: string;
+ Category?: string;
+ } & IConcurrency> {
+ return this.GetVersionCache(key, "ProductEntity");
+ }
+
+ /**
+ * @author Aloento
+ * @since 1.0.0
+ * @version 0.1.0
+ * @liveSafe
+ */
+ public static Lexical(key: number): Promise<{
+ Description?: string;
+ } & IConcurrency> {
+ return this.GetVersionCache(key, "LexicalEntity");
+ }
+
+ /**
+ * @author Aloento
+ * @since 1.0.0
+ * @version 0.1.0
+ * @liveSafe
+ */
+ public static Photo(key: number): Promise<{
+ Cover?: boolean;
+ Caption?: string;
+ Order: number;
+ ObjectId: string;
+ } & IConcurrency> {
+ return this.GetVersionCache(key, "PhotoEntity");
+ }
+
+ /**
+ * @author Aloento
+ * @since 1.0.0
+ * @version 0.1.0
+ * @liveSafe
+ */
+ public static Type(key: number): Promise<{
+ Name: string;
+ VariantId: number;
+ } & IConcurrency> {
+ return this.GetVersionCache(key, "TypeEntity");
+ }
+
+ /**
+ * @author Aloento
+ * @since 1.0.0
+ * @version 0.1.0
+ * @liveSafe
+ */
+ public static Variant(key: number): Promise<{
+ Name: string;
+ ProductId: number;
+ } & IConcurrency> {
+ return this.GetVersionCache(key, "VariantEntity");
+ }
+}
diff --git a/src/ShopNet/Product/Entity.ts b/src/ShopNet/Product/Entity.ts
deleted file mode 100644
index bc6583f..0000000
--- a/src/ShopNet/Product/Entity.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { IConcurrency } from "../Database";
-import { ShopNet } from "../ShopNet";
-
-/**
- * @author Aloento
- * @since 1.0.0
- * @version 0.1.0
- */
-export abstract class ProductEntity extends ShopNet {
- /**
- * @author Aloento
- * @since 1.0.0
- * @version 0.1.0
- */
- public static Product(key: number): Promise<({
- Name: string;
- Category?: string;
- Description?: object;
- } & IConcurrency) | void> {
- return this.WithVersionCache(key, "ProductEntity");
- }
-
- /**
- * @author Aloento
- * @since 1.0.0
- * @version 0.1.0
- */
- public static Photo(key: number): Promise<({
- Cover?: boolean;
- Caption?: string;
- Order: number;
- ObjectId: string;
- } & IConcurrency) | void> {
- return this.WithVersionCache(key, "PhotoEntity");
- }
-
- /**
- * @author Aloento
- * @since 1.0.0
- * @version 0.1.0
- */
- public static Type(key: number): Promise<({
- Name: string;
- VariantId: number;
- } & IConcurrency) | void> {
- return this.WithVersionCache(key, "TypeEntity");
- }
-
- /**
- * @author Aloento
- * @since 1.0.0
- * @version 0.1.0
- */
- public static Variant(key: number): Promise<({
- Name: string;
- ProductId: number;
- } & IConcurrency) | void> {
- return this.WithVersionCache(key, "VariantEntity");
- }
-}
diff --git a/src/ShopNet/Product/Get.ts b/src/ShopNet/Product/Get.ts
index 98d4d07..15e74b2 100644
--- a/src/ShopNet/Product/Get.ts
+++ b/src/ShopNet/Product/Get.ts
@@ -1,35 +1,31 @@
-import dayjs from "dayjs";
import type { Logger } from "~/Helpers/Logger";
import { IComboItem } from "~/Pages/Admin/Product/Combo";
-import { IPhotoItem } from "~/Pages/Admin/Product/Photo";
-import type { IProductInfo } from "~/Pages/Gallery";
-import { ShopNet } from "../ShopNet";
-import { ProductEntity } from "./Entity";
-// import demo from "./demo.json";
+import type { IGallery } from "~/Pages/Gallery";
+import { ProductData } from "./Data";
/**
* @author Aloento
* @since 0.5.0
* @version 0.2.0
*/
-export abstract class ProductGet extends ShopNet {
+export abstract class ProductGet extends ProductData {
/** "Product", "Get" */
protected static override readonly Log = [...super.Log, "Product", "Get"];
/**
* @author Aloento
* @since 0.5.0
- * @version 1.0.1
+ * @version 1.1.0
+ * @liveSafe
*/
- public static async Basic(prodId: number, pLog: Logger): Promise {
+ public static async Basic(prodId: number, pLog: Logger): Promise {
const log = pLog.With(...this.Log, "Basic");
- const res = await ProductEntity.Product(prodId);
+ const res = await this.Product(prodId);
if (!res)
throw new Error(`Product ${prodId} Not Found`);
- const list = await this.PhotoList(prodId);
- const cover = await this.FindCover(list, prodId, log);
+ const [_, cover] = await this.PhotoList(prodId, pLog);
if (cover)
return {
@@ -57,6 +53,7 @@ export abstract class ProductGet extends ShopNet {
* @author Aloento
* @since 0.5.0
* @version 1.0.1
+ * @liveSafe
*/
public static async Combo(prodId: number, pLog: Logger): Promise {
const log = pLog.With(...this.Log, "Combo");
@@ -68,14 +65,14 @@ export abstract class ProductGet extends ShopNet {
const variType: Record = {};
for (const typeId of combo.Types) {
- const type = await ProductEntity.Type(typeId);
+ const type = await this.Type(typeId);
if (!type) {
log.error(`[Mismatch] Type ${typeId} not found. Combo ${combo.ComboId} : Product ${prodId}`);
continue;
}
- const vari = await ProductEntity.Variant(type.VariantId);
+ const vari = await this.Variant(type.VariantId);
if (!vari) {
log.error(`[Mismatch] Variant ${type.VariantId} not found. Combo ${combo.ComboId} : Type ${typeId} : Product ${prodId}`);
@@ -95,64 +92,52 @@ export abstract class ProductGet extends ShopNet {
return items;
}
- /**
- * @author Aloento
- * @since 0.5.0
- * @version 1.0.1
- */
- public static async Carousel(prodId: number, pLog: Logger): Promise {
- const log = pLog.With(...this.Log, "Carousel");
-
- const list = await this.PhotoList(prodId);
- const photos: IPhotoItem[] = [];
-
- for (let i = 0; i < list.length; i++) {
- const id = list[i];
- const p = await ProductEntity.Photo(id);
-
- if (p)
- photos.push({
- Id: p.Order,
- Cover: p.ObjectId,
- Caption: p.Caption,
- });
- else
- log.warn(`Photo ${id} not found in Product ${prodId}`);
- }
-
- return photos.sort((a, b) => a.Id - b.Id);
- }
-
- /**
- * @author Aloento
- * @since 0.5.0
- * @version 0.1.0
- */
- public static async Lexical(id: number): Promise {
- // await this.EnsureConnected();
- // return JSON.stringify(demo.editorState);
- return "This is a demo";
- }
-
/**
* @author Aloento
* @since 1.0.0
* @version 0.1.0
+ * @liveSafe
*/
public static ComboList(prodId: number): Promise<{
ComboId: number;
Stock: number;
Types: number[];
}[]> {
- return this.WithTimeCache(prodId, "ProductGetComboList", dayjs().add(1, "m"), prodId);
+ return this.GetTimeCache(prodId, "ProductGetComboList", (x) => x.add(1, "m"), prodId);
}
/**
* @author Aloento
* @since 1.0.0
- * @version 0.1.0
+ * @version 1.0.1
+ * @liveSafe
*/
- public static PhotoList(prodId: number): Promise {
- return this.WithTimeCache(prodId, "ProductGetPhotoList", dayjs().add(1, "m"), prodId);
+ public static async PhotoList(prodId: number, pLog: Logger): Promise<[Awaited>[], string]> {
+ const log = pLog.With(...this.Log, "PhotoList");
+
+ const ids = await this.GetTimeCache(prodId, "ProductGetPhotoList", (x) => x.add(1, "m"), prodId).catch(log.error);
+ let list = [];
+ let cover = "";
+
+ for (const photoId of ids || []) {
+ const photo = await this.Photo(photoId).catch(log.error);
+
+ if (photo) {
+ list.push(photo);
+
+ if (photo.Cover)
+ cover = photo.ObjectId;
+ } else
+ log.warn(`Photo ${photoId} not found in Product ${prodId}`);
+ }
+
+ list = list.sort((a, b) => a.Order - b.Order);
+
+ if (!cover && list.length > 0) {
+ log.warn(`Product ${prodId} has no cover photo, using first photo instead`);
+ return [list, list[0].ObjectId];
+ }
+
+ return [list, cover];
}
}
diff --git a/src/ShopNet/Product/demo.json b/src/ShopNet/Product/demo.json
deleted file mode 100644
index 889363d..0000000
--- a/src/ShopNet/Product/demo.json
+++ /dev/null
@@ -1,196 +0,0 @@
-{
- "editorState": {
- "root": {
- "children": [
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "These big teahouses are gone now. A few decades ago, there was at least one in every city. Tea was sold here, as well as simple snacks and food. People who played with birds would come here every day to rest their legs, drink tea and make the birds sing after they had had enough of playing with paintbrush and yellow birds. They also came here to discuss matters and to play matchmaker.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "In those years, there are often fights, but there are always friends to mediate between the two sides; thirty to fifty mouths of fighters, by the mediator, they will drink a bowl of tea, eat a bowl of rotten meat noodles (big teahouse special food, cheap, made up of fast when), you can turn the war into peace. In short, this is a very important place of the day, something or nothing can come to sit for half a day.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "Here one could hear the most absurd news, such as how a big spider somewhere had become a spirit and was struck by lightning. Strange opinions can also be heard here, such as building a big wall all along the seashore, which is enough to prevent foreign soldiers from coming ashore. You can also hear about the new accent created by a Peking opera singer and the best way to fry opium smoke.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "It was also a place to see someone's newest curiosity - an unearthed jade fan pendant, or a three-colored snuff bottle. This is such an important place that it could be considered a place of cultural exchange.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "[We are about to see such a teahouse now. [In the front door is the counter and the stove - in order to save some trouble, our stage can not stove; some pots and spoons in the back of the sound will be enough.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "The room is very tall, with long and square tables, long and small benches, all of which are teahouses. In the backyard, visible through the window, there was a high pergola, under which there were also teahouses. Inside the house and under the pergola there are places to hang bird cages. A note saying \"Don't talk about national affairs\" was posted everywhere.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "Two tea drinkers, whose names are unknown, are squinting, shaking their heads, and singing in a low voice. Two or three tea-goers, whose names are also unknown, are admiring the crickets in the tiles. Two men in gray overshirts-Song Enzi and Wu Xiangzi-are talking in low voices, and it looks as if they are the case officers (detectives) of the North Yamen.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "[There is another group fight today, said to be over a domestic pigeon, causing a dispute that must be settled by force. If a real fight breaks out, it will take a life, because the fighters who are being asked to fight include the brothers of the Good Fight Battalion and the treasury soldiers, all of whom are very powerful.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "Luckily, they couldn't really fight, because before the two sides could get the fighters together, someone had already interceded - and now the two sides were meeting here. Three by three, the fighters, all cross-eyed, short dress, at any time to come in, to the backyard.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- },
- {
- "children": [
- {
- "detail": 0,
- "format": 0,
- "mode": "normal",
- "style": "",
- "text": "[Master Ma Wu is in an unobtrusive corner, sitting alone, drinking tea. [Wang Lifa sits high up in the counter.",
- "type": "text",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "paragraph",
- "version": 1
- }
- ],
- "direction": "ltr",
- "format": "",
- "indent": 0,
- "type": "root",
- "version": 1
- }
- },
- "lastSaved": 1691673956427,
- "source": "Playground",
- "version": "0.11.3"
-}
diff --git a/src/ShopNet/SignalR.ts b/src/ShopNet/SignalR.ts
index a7295cc..f60c19f 100644
--- a/src/ShopNet/SignalR.ts
+++ b/src/ShopNet/SignalR.ts
@@ -5,7 +5,7 @@ import { NotLoginError, NotTrueError } from "~/Helpers/Exceptions";
import type { Logger } from "~/Helpers/Logger";
import type { AdminNet } from "./Admin/AdminNet";
import { Common, Shared, type IConcurrency } from "./Database";
-import { ShopNet } from "./ShopNet";
+import type { ShopNet } from "./ShopNet";
/**
* @author Aloento
@@ -73,21 +73,56 @@ export abstract class SignalR {
throw new NotTrueError();
}
+ /**
+ * @author Aloento
+ * @since 1.3.0
+ * @version 0.1.0
+ */
+ public static Index(key: string | number, methodName: string): string {
+ return `${methodName}_${key}`;
+ }
+
+ /**
+ * @author Aloento
+ * @since 1.3.0
+ * @version 0.1.0
+ */
+ protected static async UpdateCache(
+ this: INet, action: (raw: T) => T, key: string | number, methodName: string, exp?: Dayjs
+ ) {
+ const index = this.Index(key, methodName);
+ const find = await Shared.Get(index);
+
+ if (!find)
+ return;
+
+ const data = action(find);
+
+ if (find.QueryExp)
+ await Shared.Set(index, {
+ ...data,
+ QueryExp: dayjs().add(1, "m").unix()
+ }, null);
+ else
+ await Shared.Set(index, data, exp || null);
+ }
+
/**
* @author Aloento
* @since 1.0.0
- * @version 0.2.1
+ * @version 0.3.2
+ * @liveSafe
*/
- protected static async WithVersionCache(
- this: INet, key: string | number, methodName: string, admin?: boolean
- ): Promise {
- const index = `${methodName}_${admin ? `Admin_${key}` : key}`;
+ protected static async GetVersionCache(
+ this: INet, key: string | number, methodName: string
+ ): Promise {
+ const index = this.Index(key, methodName);
const find = await Shared.Get(index);
if (find && find.QueryExp > dayjs().unix())
return find;
- const res = await this.Invoke(methodName, key, find?.Version);
+ const res = await Promise.resolve(this.Invoke(methodName, key, find?.Version));
if (res === true) {
Shared.Set(index, {
@@ -98,10 +133,12 @@ export abstract class SignalR {
return find!;
}
- if (!res)
- return Shared.Sto.delete(index);
+ if (!res) {
+ Shared.Sto.delete(index);
+ throw new TypeError("Empty Response");
+ }
- Shared.Set(index, {
+ await Shared.Set(index, {
...res,
QueryExp: dayjs().add(1, "m").unix()
}, null);
@@ -112,49 +149,24 @@ export abstract class SignalR {
/**
* @author Aloento
* @since 1.0.0
- * @version 0.1.1
+ * @version 0.2.0
+ * @liveSafe
*/
- protected static async WithTimeCache(
- this: INet, key: string | number, methodName: string, exp: Dayjs, ...args: any[]
+ protected static async GetTimeCache(
+ this: INet, key: string | number, methodName: string, exp: (now: Dayjs) => Dayjs, ...args: any[]
): Promise {
const res = await Shared.GetOrSet(
- `${methodName}_${key}`,
+ this.Index(key, methodName),
async () => {
const db = await this.Invoke(methodName, ...args);
return db;
},
- exp
+ exp(dayjs())
);
return res;
}
- /**
- * @author Aloento
- * @since 1.0.0
- * @version 0.2.2
- */
- protected static async FindCover(this: INet, photos: number[], prodId: number, logger: Logger): Promise {
- const list = [];
-
- for (const photoId of photos) {
- const photo = await (await import("./Product/Entity")).ProductEntity.Photo(photoId);
-
- if (photo) {
- list.push(photo);
-
- if (photo.Cover)
- return photo.ObjectId;
- } else
- logger?.warn(`Photo ${photoId} not found in Product ${prodId}`);
- }
-
- if (list.length > 0) {
- logger?.warn(`Product ${prodId} has no cover photo, using first photo instead`);
- return list.sort((a, b) => a.Order - b.Order)[0].ObjectId;
- }
- }
-
/**
* @author Aloento
* @since 1.0.0
diff --git a/src/ShopNet/Table.ts b/src/ShopNet/Table.ts
index 05240fa..40457e5 100644
--- a/src/ShopNet/Table.ts
+++ b/src/ShopNet/Table.ts
@@ -15,10 +15,10 @@ interface ITable {
/**
* @author Aloento
* @since 0.3.1 MusiLand
- * @version 0.2.1
+ * @version 0.3.0
*/
-export class Table {
- public readonly Sto: Dexie.Table, string>;
+export class Table {
+ public readonly Sto: Dexie.Table, string>;
public constructor(public readonly DB: Dexie, public readonly Name: string) {
this.Sto = DB.table(Name);
@@ -28,13 +28,14 @@ export class Table {
/**
* @author Aloento
* @since 0.1.0 MusiLand
- * @version 0.2.0
+ * @version 0.2.1
+ * @liveSafe
*/
- public async Get(key: string, expire?: (x?: ITable) => Promise): Promise {
+ public async Get(key: string, expire?: (x?: ITable) => Promise): Promise {
const find = await this.Sto.get(key) as ITable | undefined;
if (find) {
- if ((expire && await expire(find)) ||
+ if ((expire && await Promise.resolve(expire(find))) ||
(typeof find.Exp === "number" && find.Exp < dayjs().unix())) {
await this.Sto.delete(key);
return null;
@@ -50,8 +51,9 @@ export class Table {
* @author Aloento
* @since 0.1.0 MusiLand
* @version 0.2.0
+ * @liveSafe
*/
- public async GetOrSet(
+ public async GetOrSet(
key: string,
fac: () => Promise,
exp?: Dayjs | null,
@@ -59,15 +61,16 @@ export class Table {
): Promise {
const res = await this.Get(key, expire);
if (res) return res;
- return this.Set(key, await fac(), exp);
+ return this.Set(key, await Promise.resolve(fac()), exp);
}
/**
* @author Aloento
* @since 0.1.0 MusiLand
* @version 0.2.1
+ * @liveSafe
*/
- public async Set(id: string, val: T, exp?: Dayjs | null): Promise {
+ public async Set(id: string, val: T, exp?: Dayjs | null): Promise {
if (!val)
throw TypeError("Value cannot be null");
@@ -82,7 +85,7 @@ export class Table {
const time = (exp || dayjs().add(1, "week")).unix();
if (exp && time < dayjs().unix())
- throw RangeError(`Expire time [${time}] cannot be less than now`);
+ throw RangeError(`Expire time [${time}] cannot be less than now [${dayjs().unix()}]`);
await this.Sto.put({
Id: id, Exp: time,
diff --git a/src/ShopNet/User/Get.tsx b/src/ShopNet/User/Get.tsx
index 32ace04..8e06d08 100644
--- a/src/ShopNet/User/Get.tsx
+++ b/src/ShopNet/User/Get.tsx
@@ -1,7 +1,6 @@
-import { Toast, ToastTitle } from "@fluentui/react-components";
import { useConst } from "@fluentui/react-hooks";
-import { useRequest } from "ahooks";
-import type { Options } from "ahooks/lib/useRequest/src/types";
+import { useLiveQuery } from "dexie-react-hooks";
+import { IPersona } from "~/Components/ShopCart/Persona";
import { NotLoginError } from "~/Helpers/Exceptions";
import type { Logger } from "~/Helpers/Logger";
import { useErrorToast } from "~/Helpers/useToast";
@@ -11,54 +10,39 @@ import { ShopNet } from "../ShopNet";
/**
* @author Aloento
* @since 0.5.0
- * @version 0.1.0
+ * @version 0.2.0
*/
-interface IuseMe extends IConcurrency {
- Name: string;
- EMail: string;
- Phone: string;
- Address: string;
+export interface IUserGetMe extends IPersona, IConcurrency {
Admin?: boolean;
}
/**
* @author Aloento
* @since 0.5.0
- * @version 0.1.0
+ * @version 0.2.0
*/
export abstract class UserGet extends ShopNet {
/**
* @author Aloento
* @since 1.0.0
- * @version 0.2.1
+ * @version 0.4.0
*/
- public static useMe(pLog: Logger, options?: Options, suppress: boolean = true) {
+ public static useMe(pLog: Logger): IUserGetMe | void {
const log = useConst(() => pLog.With("|", "Hub", "User", "Get", "Me"));
- const { dispatch, dispatchToast } = useErrorToast(log);
+ const { dispatch } = useErrorToast(log);
- return useRequest(() => {
- this.EnsureLogin();
- return this.WithVersionCache(0, "UserGetMe");
- }, {
- ...options,
- onError: (e, req) => {
- if (e instanceof NotLoginError) {
- if (suppress)
- log.debug(e);
- else
- dispatchToast(
-
- {e.message}
- ,
- { intent: "warning", timeout: 5000 }
- );
- } else
+ const res = useLiveQuery(() => this.GetVersionCache(0, "UserGetMe")
+ .catch(e => {
+ if (e instanceof NotLoginError)
+ log.info(e);
+ else
dispatch({
Message: "Failed to Get Your Info",
Error: e,
- Request: req
- })
- }
- });
+ Request: ""
+ });
+ }));
+
+ return res;
}
}
diff --git a/src/ShopNet/User/Post.ts b/src/ShopNet/User/Post.ts
index cd5da34..79e99df 100644
--- a/src/ShopNet/User/Post.ts
+++ b/src/ShopNet/User/Post.ts
@@ -1,24 +1,28 @@
import { useRequest } from "ahooks";
import type { Options } from "ahooks/lib/useRequest/src/types";
-import { IPersona } from "~/Components/ShopCart/Persona";
+import type { IPersona } from "~/Components/ShopCart/Persona";
import { ShopNet } from "../ShopNet";
+import { IUserGetMe } from "./Get";
/**
* @author Aloento
* @since 0.5.0
- * @version 0.1.0
+ * @version 0.2.0
*/
export abstract class UserPost extends ShopNet {
/**
* @author Aloento
* @since 0.5.0
- * @version 0.2.0
+ * @version 0.3.1
*/
public static useUpdate(options: Options]>) {
return useRequest(async req => {
this.EnsureLogin();
const res = await this.Invoke("UserPostUpdate", req);
+
this.EnsureTrue(res);
+ this.UpdateCache(raw => ({ ...raw, ...req }), 0, "UserGetMe");
+
return res;
}, options);
}
diff --git a/vite.config.ts b/vite.config.ts
index a38a46a..b3d0dbc 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,11 +1,12 @@
import react from "@vitejs/plugin-react-swc";
import path from "path";
-import { defineConfig } from "vite";
+import { defineConfig, splitVendorChunkPlugin } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
+ splitVendorChunkPlugin(),
],
resolve: {
alias: {