From 0806eb230896cc06ef4c0d9ee36e364b5a28322a Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 1 Apr 2026 15:09:40 +0800 Subject: [PATCH] feat(apbdes): modernize ui, charts and refactor (Phase 1, 2, 4) --- bun.lockb | Bin 431694 -> 438277 bytes package.json | 4 +- .../apbdes/components/apbdesSkeleton.tsx | 117 +++++ .../darmasaba/_com/main-page/apbdes/index.tsx | 336 +++++++------- .../main-page/apbdes/lib/comparisonChart.tsx | 229 ++++++++++ .../main-page/apbdes/lib/grafikRealisasi.tsx | 269 +++++++---- .../_com/main-page/apbdes/lib/paguTable.tsx | 194 ++++++-- .../main-page/apbdes/lib/realisasiTable.tsx | 272 +++++++++--- .../_com/main-page/apbdes/types/apbdes.ts | 90 ++++ task-project-apbdes.md | 418 ++++++++++++++++++ 10 files changed, 1582 insertions(+), 347 deletions(-) create mode 100644 src/app/darmasaba/_com/main-page/apbdes/components/apbdesSkeleton.tsx create mode 100644 src/app/darmasaba/_com/main-page/apbdes/lib/comparisonChart.tsx create mode 100644 src/app/darmasaba/_com/main-page/apbdes/types/apbdes.ts create mode 100644 task-project-apbdes.md diff --git a/bun.lockb b/bun.lockb index ab4c7242d8f3f935a55b3a6e395389c77a662481..1c5ac726b1b870a34601c294d8cc9d67bcc39bcc 100755 GIT binary patch delta 81614 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 InLPRb021SVFaQ7m delta 77916 zcmeFad3+9M-~T-`$#9MeVogHqODrMwSc7niU96#~kdUMjk%dG{5~W3}#Z(Wp+G=T0 zl(uSVskM!@meO!li=v_Sr422f&u5O~OkLOA>w4Y4=YH`Pa@gkL98_IN@ zl;2GGF-?OtZhTC1YMiEx9+#TIZUc{riBC!1ih|18v0gQd{HpeBuZCG;Qe!8^ zCZ(lbtSuB-gy;BoPZ@oCyywPnq! zC|*wKi}=Ygr?*nCz-m5FyaTUrQ{7&gUXfgQH8p-CS zvf;5I_I>Z#S@oL8^i`ou_nVj0L`;a_m{Hoe_|!CZ^ks0CbE~N=_Z*ZXepKl$DBJUy z(&b7QLph=elTw+DRO_cGpgz;(7@rZG{rOdcXsO-gAI zD3k-(0LqH3X{BkHh1m(?F+cJ7QB^oSX>>|va@zR0t>wWmdi?lj;}K(QY+7*gcq1jv z?ogy^)~vQNw{P2MT506cx}7ZbH7Khe3}tEk+sk372_M~>-4QeeyW4mCAn? z$^w#Olbnp-Kst_Ja(ZGiqG{ukMmyawDJ42NIaAXPgv$oR#EwcI%Y0BCj|066=es?k zXh2rJTlVlFDBJoaltrBAD*1jWs}vs_8{4vZGi_RgoC4#a9J$oAl(g~BHq|yG9{c1H zieZ&pD2f`^UFNq+LaT@Dm{svpncI-)2bo<5@=;;HZ%|#1I5ac9icP?>IdIXYQ=0F z1`ED|46#aP=Rw(Bd-~Y>T)nfF4U)rm-;nwXlwB}nh%9f?U|Ije;H>Y$r)5*09xA&m z2tKoY7Csk=%EM*6=apY$m@MuoDC?Dt_|$kPs+E=9A4YkAc1p`Ync+LgfPLR#r0lSV z@X0SjS^t(e>KOhelm)*A<BXTiH z>OQ4wmCjc>30g4=5r@%$c2rsi8UVip)E{~mLqI(Z^@HwF`Z1I}w@B#=N>5>^Sn*gi zw+b{Z9>)!)RK-L hHz;d;;_tZ~J0cIl@Y2KXk+SsjA(tWO}69dRq!9{N%0%g5kgK{Ao4Q&98gt9)9r^<8*P_|<@l;woW_*qyjGI4Ivv}qVjX3!7; z%<%PW*-8JvLTt#i5MvyD=)}= z(xHskVLB&VmX_TJ23r=Jk}^IeI5wl>44E(<5sQO=51+aZ>P(CmWkyj5XS(jFP$g)W zmt;>ZgE|d>vc(Chv8kg`fe|z1MD&{_Cx{NMFc1;CB7j5rjHipE)8b;0Aa1rS@CK9_ zo`bT7;&A5T2u_Z}rU&tcdU#=cyHkl4-8;Q1%lDk<>ceL-m7#3MZ6sw!E_+QLFpHq< zFwc(W^|`X6PR+G&! zWjXJIvl^+<8L{B@_a*(aUI42KmZI`F{FaP63O+}q7nB_u4rSF_LpjB;E#hp9o$|J( z1;LMlGTt*#hA)3d_TY<9E)CX_z>}H0{Q688PZZS;G!cR-hJ?i<1k=wJZMv*;5CgoWq|&xmdmdW%zSY#*c=w zrQJWUyZhG8N?t4LJsisVc7v9Mwp2V2%IKEjx7Wx;=?s+d_e0sSo1vwl%b`sF8kB4D zbIOl_R)F7I@itJT&&sZ&B9wzN16}#Qu9g|(L0Ql)C=2=+$^sUt@EOWag))80_;KUX zlQr$(CfOh7p=`i6Q1-(|Q1;I}hhx!5Qvp#bAPmZms|KwMHK3d#=Qm1!7qlAu_o1Ac z)096-`JJImR}ESN`sj1HyFCMCK0B1Y53QU9@DdExC{6|RRDNS9N315)2b!2V2}g^j zW#UAg3SGQQ9#=0zIfb&I#i3ZEqQ^zY#Eu>ppN_*#ySQ6U!Mc0o@s$E)emkI9JZLf- zhbA%Oj>v!q;Di*J;N!35K@|+nE>BI1PD{rUm=c@Di%YEvcnR=wQ07wv%8LB9Q_k_R z*r>)$7^nRLpL{=*4c!Fgkp8k4i#At=<9p@UeTV@1d-lnUH!7X6U-F4iW)ufy!NZ|X zLHjAas9M?$K9BMo96N03m_mXB@KXl_ED`A&}L4QOekFDNRD{|UY? zd=xwGSrqGYLY5O3offdqoc6>+m@=G2_!>lO}4~OUj>o3jNQ3af!Hw$0z){EFc)liuge} z7rdb?=*BgvKPdeYS`~aPv;_2BrJf#0OvUzp^s^~ylpBU!*2<-ZQ)P(7z~G?WGRP})>!MWxP6MgQ%XPclf{1oWxIBP zv-nL)*GSFEzUD783=fbQC1Zadj7m?6iys|_3dN_!W^gLMj|5!K=2VpJn+|2hF|o19 zxL2wzQsHCblVXCgTiIVp7Pwt0Zc&aO9i4{AkKd}q`Wu^?o)(V@5Suz7JvJp%D~*h* zA>*K8vgPfn$`RNLlQIIrA)svc+?tFGDz|+U+1Y zWZMvrL$sx?oLW8V$qJWH9P4sQ?AX|hw~#)IEop-YoHF&GJZDx@2|h*!Y{6 zfh?$Ku=LkKnXYt0*&>%x6p$L5#-R&Nj83LTr=&z@YM-J&w){<`h%+h|eBA z&@4-iX{+Wk39@bOMxd7$}XJ&Wrd1BS-`!@vL$vW-MOJ$ zDO^_UB`7QO9F#5c?JP4)M!XvE`#^aV)rInmqe1IJ^E&Fz)#E2n@T}~YVAMyzaA-Yf z3uql^Nu`%M$PD&CYl6QItqz?ELaR^7um;0?zDbb^O^bIfJ@sEdEV`H0WT0c~TlcX(_lhGO? zd*aV1IS0)Dk zg;HYuVsNh(*L|a8*ItA&V9uydQ>u;7?Y!!_RhM1gc;UJE6E^*x{V<~MfsuDVoOLy} zc63nJSvhMnA{Mv3U{|f#A!OK`-K)K-Zb^Hs-0KKd^egmp5h|`T6SHgmU)CntearR5M$*JJde&X=t69y6c@<*$wK?h#mFm_Mi@4 zuDJX8>l%MFvgRiZM(Ur=4bCm?Pshu7$J^E<(!bA$E2r*ZgpoajdL;d5zn$v8wbyn3o-$6lPp4XW#GR)*ILz`*ziz zwP*G1YHh;Ew{s$#9UNxdEpG=zy7gvubYxe3g1s`btGNzSq_cgnU$}V(R;WF^e>gJ8 z>DN_{xA*qzYAwY`g*q8D9u#Jr^s|Tdck3nXrTx2FlQ9^b5#()0_Yc#z*+cqw)$iE8 z{VUk(!b9}t_KpEv_3^efu&cQe%XSMEV*C_fFCOT&YGBo4QqAs|6=qF>7Xi<(qi2N~ zUsbdxuXUSxB~9yK4^IlW2EiKOl*7p1!efijO})Z={c$X|hKG6Je0=Pj&MmF}pq-o) zXtlWjUI%;4)Nt#XitTMz`!>u9!j7*!Vwv`YgfL@FWqar_x3#PguAdraorA}*DQ!1? zCd{Z<#crMGHX^Iorv|(A9Q(+SuKH%%e`r_Bs;X&S5br75H$2RWg4Y{f5q6CA0X$a5 zWTD0%Rqe^c-Bx3)Jz;=ePEC^GVYZ_us|^kF-3MJi=`yVYO_5 zK*L@-BFy-tx?S%Xw{;hgg9JD*%nZhg-QEsu*a;(Rn{xmo z7;GMg)!MO2V(oR9F}RkU5bZV&)v`Z{cANFE2Dh~XzYVv>z+$;YY|I1eLwM{u-CiFV z=6eBNJ9tGsHMVbtw=}BPu>(fCt(UQUbBcP~`mHeQ1iZHJyqs)W25DMf$3wkcFTv{$ zPvn%->tLe$ija8Sa)I`A(jVy;W(3x?_rbJqtT=rgYZ9!U zw2WO1?JaR`qgW%`h<6+AMt1jjx4ESex z!1^4P?7f?l!mL~HTB2ukaWhH}GwL?Ar(t#uZEEjJbX!H5$*%RbC%hVF3~FW%O>$dr z14cOgeIzl=x(LtBo)tIUdIwi?>3P`8D}XrIhlLx1LhbG; zZr?94ienJVGo>o=7%*GnSZr(eN(nbpVYQ}Z%ui%%^@Y~~o{Q_E z^)@`t3XNgr33#3D#Ds7w0Lv=+0KD4eFsnB_#wzL@wJ*X$M08Gcl-@yaV^5ptHY&HZ z_f2$L12G0nXV@HuH{kL3Mk5D?S$Xg{U9pz+4>P*8voB9_TZ?gY$ioHD%!Aj-UNR!w zOaL5YU!4?gZim&H%(@SY8R$+Ay0J)bjC7|`uM~P5hokUVMH$l%?PZhUo$TO(#oo|) zn3*%-x$QZZ!d*YW>J0wZAvQM>hge5X|8UKVf`>ZDA@p4hkA)bT{1n4d($cut(N1{Y zZ8bo<5spsxJ>JN3YD(;6-$&R66{gvjuq6HlPu7)7Vo3O7)w4#zL$6^5acOx=g*o%k zI2mrQn(8(!RJs{E%4pZwZk^?}vH&psF$Wu853|<8<2vH9BfErI1F#a0D)c^w$0p0L z`|t*NJfpAMzMSng?z!zIIc}>>SKKo~SaD|xO@)U!kX_DMXn*Ny7n_D<8%GcO1`WnS zJ0D&PXC~#s;tHrahl|-wo((jfSgh{wc$gNm*Dne)a=O`DUU2&!0(9D}y47O0n#HjE zHMe_B4>uyZ+uf(Tt!V)4HqGY9d_{jcCL8?3s|gjqhAUML;|oU;~7Lr;75i*9Q+AZNdGGB`G^|WL<}cg&xVdUu%Pd8cSYw31=;Q4IT%}S!k_q;Bl~= zf-G~iTpeV(mhj~I!d&=#n(4fqVf{#X&iTstd9)p{$Za-_LEqRu)548cW9(In+}2?L zr;VaxNwlg`Y+;jeIPv*44u5pOk=0?=I(S@|be?z3bMS^cLl}m$+0%}-7}gNSx?O1X z9P44r3$2HR*5Eiz8|XtKkKpV zLhB5yHcsgDad;v_%lBtk?6e|kt z7@!mSwzK}6z4&9dx%YXr&<-3OZdI8gPd4%l76*?fRb4Eti8{XzcM@G^n-VaU3nx48 zWmuiSv0wx6{;L3UBw%k|4ja33>`|Y&T}`LSEotH23D@D) zB0#P!SbA|TJwDBDy}@k-ydYFqff#Jrtv+RT~&>yp9RWZz1FVo@46_R_X58<_ui$`vBh-JPk+pam6 zNPS+mkACSk=DchNY;{|E5XOYK$_>X~1MVOA16cAe&IB{#uihdHBc z{Pv2yZ=2g}Hpl5t%!+Yy?4e(|tq%a?T-fnKm~{r8?BvMaVOGCaJ!?CzbFIbjIKAYK z;1E3afo?~>(LsOBF1EvMM7?JB+kp$c*W`6iQD?goFjr=YPQqA6!Q;qdAsLEG6XiMQ zJM#*>p3c@GbRKrd>WVTk#E6?`ci-i<-T`guRABwwFzYAAfrky(=rF^7zMZh!ZLF{< z=4qRAKXG@s>GwLWziC;cVX5S{3C^!8!$x(*i5}kT9$K5;^aRI#-w@ z;Ppe8EN>k=c4RSL>=;*<*a6?Vee1j}D`Eb1K;i_w{B3*Hw{ENKJF+*h<-s_939k*( zKjrLKeuu}dl?zAsyK>@6?;Ut7S6=A5mdZ6j?)JOGV>+j0<{R*wdxyS;4#1>Y3y&v0c^UmDybjXCO~AJA+l!C6tx4~DqTn`!c?e!> z=b)IM5n{QP$;_Nhp4lE=M^1AiYng2vcUwCE+{jPoab^}>j!tuqht3|$`Un>1QBmjS zp7nv9aKde-e8?SJ;)!tcTUbLJD`*AxL36(E>vu(fhF^8_!0LqD8ZTmi^rF|D*8fsE>X?I?HqlzJ@k~@Y`Yp)kM`A5;l{MJ z_GN&t*K$(@U>5(Fn+*mH_}B?r2r$42y5b2ko2|n*IV>BNO!ze{T>Btlsr6360qa#x z=3B62^!!2=@(Is`EO9C<8M+Ua%&gR>Dy<%6@AyYo^DU2Wo`)r4hkWLVJrR~uw7%Vr z{GqGq+Te*Z0G87l{VjXK>8{504R-5uZnN@ccJJ1UoxNcUwA-BvH@}1Rv|}~e!XYA? z2}_2ah9yHozwm_4gVo=OcOKSo$LjbchlXk2g*Dt>a-p*~jL}5;NIU0TS98Z!<(oCP zu@;Ox1D4F-9IUYp>-LqV#X8nnSTa+e?aI=}**ng6HTS}oRjs~*AydwG_J$$RDOiJ< zfzf!UJ^PZ|H)E&##)wgP6k&&I^xS0!Ty~ou?P4F|%FenAi*p>CGb~GOcFU{Fa?V}4 z=izZ#l4qUI;5C8gtf0pA-CQ)RW_#qSCU5d(!RzE?#@l-P;c-2}4j1cD(XZv9V%qaA zVK)n}y^}TXf2G4~4bR!Xx;DdOx_{aw-39Cms5uvuUB2-wm^@ib`Nm#+&24=K*cnl9 zs~Y#U3%;@IT}K6TW&51{p*0y^1fpO$!s@XT9@|%nHzv&c@WQx}wOZ|!m#a7*;DN=Q zz4oaaZmR&0HI^5PE%wQ!#<^SLI}u(-gqfkk*f;ju zvv0Yr?*ZLTZruF`9zgqfZ^{}Bi={aCP^<;YlNX`K7z<(Y{<+UV>B*Q~;j!nP6SFxB zUQ1`G+78QEw5-5GvW{}UIszW=DB*?~t}Q-=Cu_rTy9Y1KsRPF*^jpuV68jf34qkha z*hBB^g2mbxk8P>VGk~E^L;McQ0=&5YHu@aq^A0Nuus6~;n;PTbVY^;|+iHJA4jWFU z$2z#+402-dvC9JnIob6%D$j}X%#j7J3t|;_&PIpealXi&sBrADIcSVNW+&Wto0GqD z7R>wMrg5BEa^??(#jbYFB<4bR;dbKvaO)qiIM3y&uHp$#?YQ%L1|DaOb8<5UJajH{ zJqrtaC0HH5=jA7@H(_Dd1nVNKF0`y(d9nkXy{YvDJeGuc);Y}gD!itwkD5d%|GAb{ z)su4eVAyaY>`(%cDi zq%^Ca$Muagr^8fn&%ji1+h4#z>qIc-Uy%9d1ND<>T3^K7DQV7!DI;1JVRFSN>MVEl zev#)=XK^qS;K`d`AN(Q~Td3|Y`RD|(#L{sq@lv6=2z z^VC6R0nDD#?0f@f4Qammmzh^+S~G9T-KpvH=M8x5UFQj()$EqXL!GP)<;mxpU&3qU z#MGCDSygY#MOxlNop?vnl306Z$v*#2UcbBevO{6mZg_viZ1NlaTB0!QJ$Pw_UisfW z_2je1sqnaZd#nDbLqq<^(*oh1Y~}xJsFM@SG#ktaIP9M1()kv_$7{ISR{JEW83AYT}~`dKYu#Lub2( zBW)`zdGwWk#JM!53YK43eUZ7mPjQ6YUh`*XZ%tPR;B$r6Ay|=4DOGfjm8`7J-i4^N zp{oi;7h3BItw)7cZ+szBHe?AbXRR|Hc!@2QFmHN#D`GAxv@XJu>tJKkV?AGJeN$+a zE`m_e&JU}SWBF9nyXxJXdfx<)R_mf3>jhX{8EWh+Dgvq^u1l<{ilOP|(w&PFHJVyk zUOt%9L7g?&+zZRe%&LfQa`M11oQEs};qjuTxN~oKF1%1r|5~~5dciAcN5+R4Pd_Ct zSI43G2fkU!=_fD75`A>u;g_E8PIURA>qXGiFvt`fR)0>lKl9_Bj*Ubn~M$P1mX zONhla(T>t3b?2b)w8NM8->l)FJXII9=iyoS`|vn*akJujm~p7X5pZ8_Aw=#3;7}Nc>Lix z8J=|scpP3Qrg5j7xLhCIS_j`>Z3J3G^(#7kP)ln%=rB-ccW0h~*Vk!hNCjD%w~aeH zW(+*Hb31TV1+h37x!nX|8Jg23ia6Kq>y#(2@*lwC1dw~ezW9=?-1qUp#C&+1w6fpM!;|X|_i^R% z^;qdKW&}JremTR#%q8$5oUQK#SgaMMG@e9MsU&;esg*IXlAQLl6_xiwPQYW$oh^}G zR?KUpSFl6A4YB$K%E~y=yk-aL_S5~lSldBmL-`clj$=}Bv%Vf?9)~Nh=S9^PdWcoBnykNkxYeziSlj{!L=I>Z zXCL_~tSDIocC(GDI|mA$+YocQhBufi*g zX?_PU)Hz;@*MB^g8y=5dnZv8_x;q~4T;>(V)_9KqAB;3v{^f*snhsWbvPKn%q^8SP;rwcDun>6x_23wc} zPqv~J&k0{G97v|wx zA=}`|`M@oEi6(L~dd3pheew9}7^qCa)~$pmk0@S1{9G8u3E!%zr{Cb2GvEz#=F?eN z{hc!PRbhHFQLPh>spS44*6e2TaF+v~2ak)U z+do&m7IJV48;eH~t~5Z_^`GEcKu(=PXeZ}bE|uJQdS$h5>6xQk+24o9c_VMiU4_Rr zNuDHYg~|rt%z}IEW8ulU&7S%K9;@w)yy?{njdPk44vQ7Q_XjZQv)~mTgVr8+DhG_E ze`~~az5??MEIAv{1?GBs%**s@Maho#r~!}M+(e%w!IkI z2d9yPAe@q(ExOLfiIy+Esm#-vGrop9Of>0>E$D(UF&S!Z=%j07#gx9-wl@wJ#Ug=3 zIC|G!axL6C2}|}mzT#-r>g<^iobie9;+=%%37E0cY|};8#!GV*%yem1aqC*DH0Q%q z5wO|PG9{f1bCTHF53PbVLBdfHh2}AsDpjX$SkPsJH85q}&9dEfEm6`Om@ee1v)20V^>eHZ?NummF*?t{55OOd~We8-s($s zeJ3`iH%MHKLI=LqTU?Gp2bSrBk#vyx8O)*5EYTN}Lz-h?x}~`q<^adEv`Bd%8qRsX z13Vr@mNQ=`!{h9Ajs|_ZSQ>?PmG6fcpmKyMbF@~&D69SuO%=dgyd1B^jUwM#R`%UNW%P@F69=)CWdJEyPV)8NMQFv^Syml)!SjLoB z+e6`T$~$+iy*?bQ+ZDgIJ@dPlLag&}*?MP>>05P}TrG;KVr%hPyQ}$dc|ItdidbrW zUj}@d*?MYd-y9q20&E9}3zAOQMCF>|L9AZGx5fxrAj=-e4{YokDOSbt z`XpLjy%bR;TFyphcC=_6k8R5j2xS^?ekH*Q996hzV}%?7PfiPNML&So!O0z-d4n;< zReTY`HComWr;1K(Ha2)x@2m4KskK%3;q+dOAAYDM@UsO!>>=EqcRr6R`Im}Q>2Fp3 z<4V3w@xM{={y5z?%S43T_+jKdO21b64V0h%q)eCV#QJAtz6bHc4n2k+o(xXlho8r^ zv{Nu{DLNmjA(kZSjl}9iTmm1!uPmngkpcKQgC9<^^Z4P1%J5(C!EY9f1rt@QW4qrt@!< z@p1jnzgW^LLK(FZelcBT{0)iosZ5H`|Ch=vtEhr-DdBt`S5~ZMmI|o(ACx_W{kk*Q z*sD4pDoyN29mQVL`8=*X0@^74?=aZ^l#gZADF@4=^P#dM z#zNVic*Xxt8I+*njf1i};|Yb&e7%A*Rg&SdnQ2glq${0B2Olbn$xuF(W~TC~G$-R1 z<2|qZDTMe?X--wj`N3*T(>0Mg0V@gvr{k9eokQnel$D#OIF*TCSN`8AgBIWyDMQ}hbH3|XpzsZWV1z~Yq@ zEMWf!zp9G2Y`v;DU}MQcj@rk_in*@CuX4~mPC z<%i1fUzGp266LG#U-4&iPC-`{xB=yu-GQi-xMzE-9iPog!1#aGQ2gpNPI)D;v6&WRkDsM zI+fMw1SRUMIF+Vb`Be6APblN}g0dQepzOAxQ2f(|;TOY)D;)tX3P0AsfHPt|V<~0* z#=$2~R-8&d4N5c-zc>!hK^cFl;@J$uhspwTl>fLgpBdmxH`6oVGXa?494I5qgEE8p zP=2Uv=|U*uEm8U&lr8=U%J{3H{5-DYYgGJCRCuArJO-HYM&&=QPl4}L{O^=4*@JLu zu8Q}#>LPfOTA~jjnC&~NqCKvx=P|{pG>uRm5264 z1s+$Te3js;3a8S%u6!!Zo63J&S+QH-EbwIwApC|%;DWYL8H7TaaVwP(l?Aj>K9%8Z zmH&6jpfDBg(JYTa<+46NMWE6gtb8g9h*Cb4{t)F;=?_&tmHyL8hbjKJB0NhQt^%k` zFhco{D_c5JaVq^$D*kB2spNe9CMR>e;#3Z0lJXx{o?5i=DnTlg8KkR-RQi*YPi02W zLs`)&ivOK5U6u-eT#2Ts^e@oisf7j;%z(0h*-)NI-+~s0u7L9MzoE`b&-bpfjMb_j zY5@GNmH)q}^3?jjSO7cjpBhpT{#n(qvtF|N$AA<6|DNxe9Dmj5|9u6@An6^nj0@5q zs)hea871o>e$&u#%y3p4O1*dt;q!OOc-|`ff2cUq|4l|bsTNb5%A=z=loc%rWd%w> zd6M;q^7G$Ormv*pQ=Q{KPys3nuAzJ?3$CU7|B14~wUG}iz_)la-}+R}zhG6s>wXDr`F06+f|Wr53)k1zCd zmEXTtb^QPP2&~S3C!@dOv4tB|!BijkyOsZ6)an2K6ye_`1ZP2eR5+F9Ugc96zEAm7 zcKHD)=hhJ@caT{>s0jZj%8XB|bbqG|{}JIFiVG^65$#RCKOQo)868*f1}QZ1mQIhzF)_B zbx@qg98lp$R5+F9_sXX_H|g_WuuFa- zfS!Re;|ox>IA7_nP{z9jWdU~-{~gNse=5}xi48ItSt;Weh0pwoLFpHVatYFWVIZwm z0m_6Gp^R8r@tROptQM3XD#L@6)`v2~VC9D>ZK|||(pE~_Lh(-vFN&M4OxOh;3+@JG zLEV-1fU=<8%I^bZy#C4`p!_H({%OzP7sqxioqy4?;^0c$Fk^Ak5X@p;P|^M`Do-Q- zy@FZ6>8heLR7D?GZVKjtGf3bUkM^Zd_Rn%C(|^D~rEK_$q9~sMD^-M5Nh~XM=mHo%VYd^l-Fr|aWX4-AIc44QOqwER1C_DOF&tH z%24)LO(=V&uJRi}*`N?8^695Ffx!=z0Zo-QgEE8GD*W%16=|#Dw^Q-jZS;RdfBMNo zVLlvw@=#b#&Z3xDPaX>6VEHc(iJv?a=9+^K9}?4i@=zG3Pt_Ms9tuBsDE#E1u-t|` zc_{qkp|HFbc=AyA@n^m~cNY4dheCw_R|ZcW3bTuzJQRNNQ22l2VeylP!aTb8u$VU? zo;(!Ro;(zO@=*B6L*XY6g`YeWe)3S5r$+gZm?y_44~3sR6n^qh_{l@zCl7_6JQSAC zI{yFkP}p~k{z?f^E5zs_^1sl1M6WOP9(n_@=u3UDSokHt6a?uFMYpX05nBP)Y(T5L1yj&nb8={ix5NhAyMep09*GVm+r#a50FogxF4XW*i5kS z8-TzA0KG;00f2~HfP(-=Uriikt_37_zd)3JBKj<%tk?_C>l=UpV&z_dsC@uFEM}1K zKM3I34>08*K$O@^u!$h}5WrB8c?clx0KjR2VWRH00DcDn=6nk1u<$5A>~Vl3v7R8}7(lrb0Ldcy1V9179)c9%`#r#l?*P)j z2S^h;2%?Sy)XD>xC?@0qxK02ZC&&=hPU?g8Op!^MERIl~6Ln8Po)cO$4V27K^$U0OHO8%((#YmN-e^_cK7divVwn zSr-9v39b^nD_Z>mkZ~Sh$u9u!iAw}Q7XW(Y11uAZ@&WP)9uRyWx?KX8c@bdEC4d#; z9zp0Y0K+c>tP(3P1LPC<{0gvIL|*||m=Cb$3cy<7dlew!5iJU(GHW6GPI3*hY z2@qERu;5RCAH-P#zk38+8Xn>S_K%{~1HfFuB@YnmjJQOQaUY=9Lx6K)(L;csKL8#O zoEP050pt;^c?57#+#{Izr|z?0IM&bn1uG5o$ODA?=2>P`7Q&^E{--77nTp3Z2=_u0F)4$ z2_lLC1eO3OCE`o4*#rj(N(=vz04tsXm{Jm;tk_EsRU9C=6hL{ASqi}A18|zaPt^4V z*hDbL7a%~KB#0|vlo0Jp8{PFvVpeGYzmkY?wKQT>7Olzv~OTRDI{f;Hs;YKwaWGfM*uFAoqTR+a|{Ed$_F0id23QUM^JU@Jib zVfg_pEDMn62hdP#CWt5p5aXJm7u+7RT&_cU`b_w4&o9) zMn!;LRRB7PMO6TTDgito=q$Qb1;`^LKn05;FLZy5X7v8C=nvE8lr?&2G~H* zUFg*T@(E(A1N0Q@2^LlXC|3iZw}`F*5K$Fi4?$nyTN9vwAiX9)Ke2;gMKyq0wEzZ) z3AF&CsskJ+7$mCI25{8?m{A)bN*p2BM9{nrz)+D>2OzE{zy*R~qHz#_UoC(IK>#Df zS%O@GE_DG$ig|SbGHL_dB^V_-)&mHt1F*avK#aIakVi1EKEN2Uv_8PhAON!gK%9td z01#RiU;{yd(1QW;31Wi*#)AWh^n0f-6)xIi#bG;RvuY6!5PDL{reOR$NcOEZAUVqPHWdg4bLw^w9 ze+cDHV?Dvl_5kHN1FR6yodH6_0QL~9624sk@(I$r0IU`}2o`n#sO1J&D<-%BB02&b zCs-${bp5`7IXvHB+e3SBIwc` zV2ha79U!g?z+HkbMaLcher|x}Jpi_en*_N81A7AC)nz>aGP(koy#RKK$X)>=1EeES0A6QuVAI3RWqEbIYLD-z(4 zm=FmN(G%b}!C_IYA3y=YjD7$|#SwxPy#Si`2l!6p^aqIQ4RC?rglIefz|{v}!2p0f zah6~cL6?C5r^LL00C9Z*?h^bUIt~Kxiv(Cc2;fI?lOUI1;9!6=V(DOjjD7%S6u>zV z83hp3A7BH)d7%#h$Rmgy0&r2RCzv?^pxjV^d=WhqAao$W9)iol_i2E9g7l{Wu8183 z3kLzz8U}DpOc(|bF&N-DfN?_?)ra#kjbz4fkXyPqO0psfr1=PtJGz)Q0wih($OV$$ zbkXD)5Z6$U1)E4V0b%d1+2@=tix?(e>p75OjsW0Lw4a5#gu<%cTG!zpkjl^C`h^Uqd zX)H1+O~esOQ&Be!(oEz~nv0W^7NT)Fq@|ce2^D84twgJdkk(=zrH!~mX)8KTg0vHh zDDA~fN|@-D0qG!?QaXxzlujZt6A~^~QaTHLGNg+bLUD`rl&->h4iX`vDc!_oN_XM= zJfw$+r}Pv%D7}RL6i9C|fzn6prSuimra~e`CZ(S^0ud`RG1$$sFxUe`P8LAaWPl3< zgGA$O0M~N>3$g*C#94w(1YL3fhKhMP0CCR)+$9($I!*)dn*y+W8o&r~lOUI1;0pjF z#nKl5GNuBU(*Z__$mswWo&}I1GG_s-m=187 zAWhVr4G=X0V9soSiQ*)I>qUTeF9T$VSuX=@BDhL0S+sfuAnqlAC9eQHFD?=I%>?K* z2VkmLGzTD;-~mCl==Lf=#w>s}uL4XH_XvV!0}Ou+V7gfO8bBU_&s=~P#gMrGGhYVS zN-$Gc^8i9$0Z5z&Fk5UU$R`M#5AceJpAWEb4!}WzSB1X~5b-L&6dPc!*h^4A5d1p8 ze3AJ&z>3!ZP7}N?>Mj6?nhP*z0l*vLB!O!lK)W{p7K&MK0Bj<-O0Zb85}0dmig}c` z#3jlS(QzT}LJ1FE6k@*h5 zip2n@2|g2b-$ld?B8T$1I7!(k8ZU)x60<0q#aYT0(ds?O7h)deOL2*^RdjqGvP~?a zd?jvDwu^4dP)No*C}hnt6tYv?BM5qzZCwtqTdZ7;h?J552wnwnRAjCKSg{=7G{JYG z?ng*@T;xzrh?A7>MdQ_wJTZ%MQkroLd?J552;P9j;g%sLZ@~F=#X6AF zBzFu^?{ko-^&oRT2l>qqr$}6%fVA5PQecSL8$mXaTqU`0h}N4x;ywjgvI*o*LtG~D z`wXPlW{`)5SiBh|m*fEm?iqC3g6d>!09dmHz!3Kcf<6Zr{sn-ySosA&9)Zu707b-* zF9Bw51lUU864q9L&`kh|TLFrR%>?-bf!hFzi}-B-3pWECBq$;LzXFKZ0x;z(fKp;F zK>d zxNQJSb^%lpmk9j60_e3Hpt4xB8z7h90YO#KZ4W@kc7Qc|0IG|71VK9hhJOuEQ>^?N zAdkT38-Utk$Tt8pcLHoB2ohE<3tL7@(85M-X%X zVE7S$&SK>efII@9qX2F(z?hyoi4>0@(fEcmz2Y@^RpVI(i#E{bfGxGqp62uAXM}W|i0Es^WB#6xf`2>MK z0gMyzKLIQ}1#plcN%)@ui1-JUH~{q@T&0t6(Hgwz?5GB=8C-p1q8uY0OpI#D*!8g0XR+Y zx~O{1}v5`o{Z0KIMi zye$^p0LUeHK=7{Ub`v1u3c#A10Pl%=1VL8;hTj5MCRW}8$RqH%4e)^&avNagHGr)I zD};3iAoMyw;vIlhVlzQLLEv40)gt~bz``2<2MN{+|K9*2ZURjC4Pc$vOHe=%{5!xW zBJ+2E6}JFR6MQD>763%u2AER-@VPh%zzxMc$R;t1f(->_i)eKpf(-@bOL2*U4aFaj zZDJ7x8w$#H(d|#j4zZN7Q{1EM5|IxeyTwWhwh|8^UyC6WY$YhU!g>V3R)VrmY^LmA z;Om8*#DaMIKDb~9ejgJ4I^vr5q8}49HQDNjWBtP`(p&y&%{=P)>-G6l@>7 zA$ejJL~MG5wqN!3;=O=Yrq|#Fab6f`6aEk45`5vO1N15a@S|8%1R$5-0l^v3ttdc- z0kEbhz&UY`Ajk_~xC`LCSm^@DBk-{RE{Y)*z)Wv|tpxePDh3d00wfj#xGXjkiuC2EbdaECY~7;8PZ$h!|29U}i~xtpqM% zl>-PZ1&~+{pqSW9kWUa;9-z30FAuQL7vLa43E^J>AfmLF&&DYgyqXr7AMS1JswB2l z_IfDR)%VJPFTSkeEWiI>bU ztzeeb($iUKyzFM)UoD>)pB9^%h8E6856EgGsyN&Zz4qc_#kw-N@nF8F*TL%p^WEhv z1}&<{&a9RYpBB$tZ+_&wCcx>8*wj(!@#A8&#;X~%ac8fRMzNIfV>&+WI_p;CyeN4%alT0-_Cu`ZL;dPA^xA^osE@Z{z(R|23?5Kd-X>NvBXJggrhH z%mPg-&k4|!75ED8J@-QlpL=W?YX7Det6FIgs@nT09b@k_*C!!0I5RqNoVKd0uHhb* zpI3iIdn*djel4eCSbzqz1B>ko(D`bM?C%0LmKf^wo^GzsQ!RcU!5fDS^NMg4%L~)_ z5{7KFaBYlN32$R_&cG|Re6mrnF>0`OWa#rWC= z{D%e3=elBi*HM&WHx%RhJSwt!_}o+sW2=3`^6OtIUNWjSxEcwa%jY0%Tm zC5qhze2h+8B|q#th&)HSqCLj3ZT3F}~4|@hahmJ;D#aW<$n5(Vh!#DPh%0*UL^l{Rdhc}*N%Y>!)_dVgE1K8|EyEoOos3L-p_01 z$v)?-wbyRz?7h!E<=%t)@BkjdBM^5E#{Ua}1ByUlkWZh;_fh1F^YpeZK~$YT1V90h zZ|nv_K@j&p1pDD2M8PKcj#xAsJK+e#z%Ez`Ti^g}hkdXX*1>Mr3+rJkY=aGO6n4OG zuo;fQ0+QDnh zpeEFU+E7RRR^FO7;yIhrpGf~9eS`D`a_*O+734H64n?6P6oz6@8cIM}C<8^n0jr58 zU$@K&-fU-v?BD}gAw6V)3}A;;^4-0(YxBHuHYZ=9dQJx;(GxCrOrG+cs{a2Dj_ z_Q&7~T!!Ot3a-KhI12f&F8l_POFhT~d7&oMg0c_@g&-J;fCGv`VF-c%Cf+z44?!YNH4bqh_fkm(wmclYvt{RoJ_KbMR zDHIFx{XY4|-&2rpnO^|;2B3U^&`xslZKPsQ95*WgC7}qMMJ^vRya=yBKCoI9-n0Dy z_@Ff6wf$Xz%BChPnH~PN97m)8=jfK%L62`!Am;^H1REHXnf_TZm z4U$4~kWcTW0T1wmwBQ9YB4q|2$O73wMx-<}e1SyhqyYK4=bw;@?POqu#NY<5kOY!KN{Ddhj}1~o zLim-49iSt0hn~<5WDxEIJ)i}&hh`uHadT)5ZDBDifI-k7W?-`d;cJ)#@*&>>kQ=hf zH*USzkT*(4P;&YF_gEMMvtSy?C&a@c7KfB?+{<_Vcfd~A4Zp!&h=zTz8P>zE&==&F z59H?)eu3uD0)B#qFi!fq@oXf4w|Myn_zUD`D&$8wu0dh8=Ml=!i^y-JjE4y@5&A)2 z=mTA$AvA)<@Do%5e!Win9h+i=#UV3TAOXB2eV5np3jP53xupwm1P;Si*aSOZ8$`io z*beJ}>lv3VupTzRTG$BlKt91KKSOYy@B(O`F{7rdfqXqvzL*(toj)@7*^5U8OsT|;6D3zU^?4r>4?&S7o>*_kP+;V39Mj)gb;@B^oI7(0Xjk_ z_!&H`)PFjvLndxADU(TyK!{LQ)e5#*`fuOKsVS8%|5_NT%mm;(J_ z0Q?GVpfxmus!$zDK}pz&nO$%QeuHR;fjwZMId0-p`y=q^eIOrY900}eZut&u0Lb@S zt3ovhftpYY>O%u)1kIrZw1igB2HHY<=m4FdEA)U~&>Q-|uh0)7`txT1guy@v2l*R5GiFXg~gZxO#SvUg+(LD~4upT}6nC&u*|D7x}R(aGqYL+2KxM9&=(BKIl60seV3)~*<3m~qL4Os@6hnmG~3 zL`1H~_j3$0+N4A#;$kNS$i%-KX+}UYFh|py=*k3sGswJqEy&zk=GLn~=H7DB^n#wi z)Y(rfad&n)Lr0Jr>;UzkF37xE=Fl>iuA%PMw5CZdQ)8J@%M4g%zqee}vYJ-k2$svV zu~Np&XCO1)C-4{^!UH%5GV?tPG82vl87s%YYFG}-U_MNOMlccTz<3x9qo61BfKJd6 z+T)Ba?bv7ozX0{;k{6o5&me0`KS2Yi4E3R&>Rr`(J%S5X&3CBXLpjI~rm1|! zc3HxbPzs7eQ78hz5Cje=1O*`g{J{?jKp==tVJHUJh;S*xhC~vhC5%vvmxc;Z3#x$R z+ssT&wnLygh|D}L`_-T-)PRH_x~5zTYi{dd1YIo$rKU|m+-*4)3Qgn4o3q^v#N%2) zYiJ2AjD0y~?n|cIf_Snth}e_u4$vLCkiJW2*??})6{LAZQ6db3p)eQ*K_s|=#0!Uk z5C#LFKlFoNK~^{Av@(`CznY2n=2&0o1HKS3gg=tlNEiXbK?GyK%!C+`W8+|KyyLPz z0p`I>$PF_)yaTpF6l?{Nn?`oAEpqd?7}*0S z;RqaneXt*5;1C>y!*CQ%z%e*(g!7~w&%kMrQp>h*AMU|jxC6I99PT1qfb(zzuES-x z1lQmyTron)l*n#_WJuyXg5Mz)UOo^pXQbeUJ=MeuY@Me z+5ZK^cS8xAfZ5$NRU7NzyE11s51FdwzL{1#bYza*3e00N-!`|~8gkK*vPj-cnN(^g zW4{YwJb8pmHx70Mb6AtSO5sh#$3}Ui6~t&BkZn_LCS>lPLM9axiOqq~59A`DFZ6-l zAaSaK_Uk?}?HvGeMIlNF5y-x{l^H3V?dc$fO?@#u6o!DDc!OaOh_2|3A{+)IVFV0^ z^&Fo@I0?qW7)fL_On`+5#}kf&i7*8w!&F#;Oc6>KC)+YmEP$CDTSz#AP>zXg9^12F z7R-e?26Ai}EClIN7Z66AV`DKJi(n}%f#tye+SE&YP~quNA^Dv{tX}DJ^TsLa00~s9>V=3EZh3O2y^4>*CPle!9#FR6hRUY<1*2fZ80X{ z0gwy{$Ke`2`<6~I1T6F6r2Rfo)|j=B0Fmw z6WL|B0@vXth;Q5>6l7cCnYLotegco-5j=tW-o`MJ^d;uafkDK93jt$4?8^S+8 z3`$8P-fQ>^-htGhG>O!dIG*fF4N8;A@%DsrIrEuqYB9nk7dy#8u5F|`rP`a3kd)kw zV-m{0(Hz&ezJ5*0@%`w0F^=VATNV!!Ln25BHn2hhuz)Ni$b!OG;z(Nh{EwbsIIq|? zwB|{XiG%XPwizLVMI~%#^-G$9?Xu9!MZIol^|b_BRN02sk`c0uDZdW;Gsw!teQY-( zl;uoW)@%UvVFbtP5!MB{y(3L6w|nH)PkE40K(1t~KxL4bN+rUIPywof%v|KSgw@z* zJ3{;E+8XT0eIv<)tgSW$GjU1G+?Ms$X0RUvLOZtGLK|oetw7{0LDpsW|1&YI0=jWr z)@q~~_sNg9NSk(Irz>;;snRfz1z*|jXN0oI(;o(cECOpyXEcE2V@BvJfYvKD438FXxhQJ^g3}Ubv41?h?5+=ham;_=_bj9FA7z-0% zJd888<+#|E4D1JqBk?735%>5big)24$VI?;Ldm^EoCUJZau^PQWI&7^0JBt*X~~pn z+|1Baj!A~Z=2k+nX~vh#5GO**%`|o-H=-CfVM$1GD@LRy%nV6nsU@@Y%8*NjqLLgI)_ zoIh?HGh-r?rjMIJGrpV%A7F}{=5Z5{%m{L9B$$S`vK_Z3%#y~9`@aeyGO;W1;@XZd z6BLE-m0pg=O(YSWlzA*}2F(n~Qv)J5GcL#F43#Gc;_AzN$l9_j|B?-P{y~=EPlK%A zuK-!wuLUxG$U>n%h#?vF^Rt~7YC;H9hRw(_5>|q8Py&iWF_6a`f}t=Jg0kpVrm2JE zr)Oog(tJ=NGu!FG3p`Npln~^(2p*WwRz2N_oQ7@5lo(D2k|{|%1K7bEGJ!mBAv)P0 zs}bfP^aYuK<&0oMN@kWSAKOwgnLXzr6r;Hz7yAVW{XjA)+w#balp>HY0A%7M8FxTY zC}JQrQ-OeTqcZ^$&uM^OF7san!zvd6Vw4Q*Z}H7J*aDJHzjNW z4MCP~ekN=TjX;)p1X<>hj0u7a>;;fOASjQWZSeSg=IfNGcE#2#0(_?sanZ|M353o z;yod5Q;1=yX0vL0Ar~7`-C{42P--|F!ay=1HP;^`^S!10rR4oUs<o6*3v2RkL`oc&uqiB1!^cOk|Q7K@u=)z}y#I@sYS0 zma3L^H=R)uoXx(e~^G6Afz+pH92jKw3z<$^V(Xbcxz;Cb{cEL{A z0ox%8A~x}7Gi-$%k`SS+Pi-?o*_Ij23HGnUMF@gx-~m_R0$c&(NxCe6VK0E{&w4M?^foJeLJckb;Bi|}`4}ZZs_!HiO_`(~) zKOiG4mGEzUs(@;8+X&~pYbR;8aHt~8{@{1c^oHg#gX-`H%x#J=> z=MrD+YUjW7aApE7lxQmZKZEJ@(s_tn5*EXfYtyKCw!}SVo<*|4Ys21t!iONC8~f5k z$q41zD5=%Xg%CUPkhMHECl6p(ZpuqgmQ!_SLLmW@jV4opp)Sz|0R-RS-p~W>c$j{#|h{i{f9Le%gFIxLH z&sE8g1h7`)q3j#2UK!mzNE(e}uBoooT>a!D8UcO<{m}4MH8)!G+VY{0OVu7`^-Q8| zqB}vg4zr%l=;f(L^?lsXFR1w7fkZ7xvi_XKs^&mzdS0CEyvdqAV_Ec463wsh#6s0p z)@xvN`WNOXPzaqa>u63f>pJXo3FG$K?h6YN8q{+AgYZCbE?1iKd#Y0lvu1apUwsEXN zL+UQ=m#h``u0KB>jlzC~{0h;>8F9zf{b|XJ^)vT6y zOlsXAYhZ?lne<#fSur~0rArCBSzIr2L~^Ji`&d0y%E4Bf*LM>R_A9KSBdreQH`tob z7UDy#Xw7D9P8vzSg~m z8+|RuQ$$304b9W9lf~7cdxy)|Y^sxJoJAuY8b#KXE9Y(*JHg_*fFsmWq+!FfWieuS zd@siIVOAf@)Ep}7Fl!#m#vCegsnyH2kx?O&l8l$sHnAz|isI@SJaeQPl&$Uw_itV? zhv7n+tHAP-(T|3;5N{0d<3Fa`In|zFRxd|4)+@LJ6BT0oM zxnEG(yMLCijYLkM0DqTmIhEURN|`#BuF<3Fj@W!x@~_scYrdW>mnuEnTHe-`VI_@L znU=1()q>$xANxKIiN~#5@n%GwSsRa9Tsd%;%?d2!Nf1Ulo>Kf|rS1`!0pvwm| zq_GACTL4kl^;b-wkB>; z^m>k}{AJ71>|xI8@9M82M_EHHTLRRbQCQr9IZ69afSNbj>ZLM_wq~&V1nSY}Wbe@; z*~nk)50tMVEW2Go!8T9JA=M#KpSie>3X$eSe-c+=RR>MIv3? z);AkoP2H82&I$*@JcCX_)nyDdA7g0bp1C1+fne8SMqF}x4v9N)+u8n}?|9lm>vFy%la$H8TFb7t%y`NMi)&dpiD z>cBWkHnFIBPpIyUw`Qc zi9d#pNh~l7%vZQrB$a%sAnS`cU^sf>>KLJBbCil6-aNhSx%K! zv6Cp~^fD^zWWohyR0BeXPg(u+Ptvvcp=Y&c?XtLrJNyD^JC_AWl2B#kCuRCAPw^Sk zkw|YwwXZCz_DrUfC(0?eDb`sQ*9vOI6g=3wg1RupTF)`8qHc58$7ZRs*q&CUc>aEY zw4}=D^#wyL5EoocOKYd0E_s#~HJi$a4AZFhIwY#cd7D4kEr z+q3TnjBnQ0-Swa$c|s_CXXd$q{_(1&WO`gA<7a1FguK6i56&@F5EYa|dv0-R$*YN$vw9OKZCbNhL##`SL& zk1mf!Fy|1Nn}J07%r#vDwseYZIS+|3&4~z6rzCEXntJ8L3>{dfPM!ibE&JNpe-Mcj z>~P!hDOHKzt&;;4m&!>g9wGiQD< zY}(1EK8>6j{)VK)s_iXL9j;u|DXCmb&6BvT&|oSO`DNSn4VSjW?r>^EB4J_?x%`Xo zgGA{sR&q+_)>6-jYuQyxC7gkyEoq?Y5!(Cyq}O5cZACAHW)3MqDFfv!4s;pvliEFl zvdlyyEjFvIJ^O2;<%iBWHP-*6UZLSQh=zGrakStl*V@dRu){K>= z^*?`7C1(;hMMK?vyC*!}-J`!(9P2reNdI@Q*6N5NO?@6XVIyV z^Y2Eb*Eu!%HdN7KeKHzSQw=X|aQhl`p}13HogvBpc}-yIa;F|SCC3`76tjr?$k1q< z>}%rjO&TS0YFHZSRx3_#bbb4cHR2gYoq0D>O^9nRhK4uk{v4d{_mkKExa-tt)JRR7 z#p%=cC$(V_r@)O_)(nnnjrGCeddaBZv|-!lpdNrDGl%)vkTfjS)qXGcnBkhFU|~GC zV`G(XHVqoqSlwA@^|ayj;~J}G9CFMjl8lyJ7Y`WG*|+9I!yLoqMnmG#^i}fqqdq^? zBo0X^hR1Cs?jK+K5U$xmw5RzbrPSYCcV)Ag<(+>u2RZ2kRx!5MQcyddiX+YJRk)5iDIoT|@Gr+~~zC=Jx2I zNwjXH{m&{~;zpw3McfyEv?==P+%xF{rIIN33?$M8Mh}`c_5IH9#7K;DIaw2Rg1DA! zO{PZ?bZk6*E|$V5iF9tu8oJ?A}fF2}$-Xg{qf|vYsa&fqHL)#u1QAIbZ7eMRdb%{&|Szi&^|EZt0XoBz+c zky2XnHCKD&IF_VL_QK6|zkKnmvqz>5gYQXMWJd1qGNHM0TY%>5=E`>gy;J`ds@DR} zlA$fs3fVXFqUZcuE7;?=q*gnei<-wt9vt7T>4H)XgIekRd;8h3Kh2*|ET)+=$ zR%;f1%XeC9kkmCNnc3=Ty$gN+#0-+_4!ynt&33R{YOKQW7<&v}C!N0=<-=8+y;3K=himuo z$%cT{&9YM($|4hz)}2(nrA%Fn>pcl)E#*4U?C~xvwFa3xmW-WM_GL8ie^kLYd8%&e z?J{Tg`R(}YZmP+0>#w#K-MM(zuh(95SFe^^BaK5T2Us)NyZ6v%LiWFv zd#h)wxRyHAOI2M>RqLUT#jlUrxjK#>mJ_d`3O)OBpHr_w&%SET8k%l$U$tiq*<8|B zU0H((K7Hl8mdQi)U-gc3Wz9@y=S)7wOqWa)mf?gL&s-0B2N zAFAv+Yrby>i}Y8&uCs>5(JyK0kL|Bd=qil$Y3O(TeqOC&w2@LFk-2Q+GoSbWo&2U; z05I2-E{;VRzx6oelK!gkdh4t>W-a)L`v$T}m}dj^ultOT)@*8jq&0OsWgN;7x@}?H z{%*qt1k(zBVS2aS)}`dxXSuFwvvQ{TtoM}*Q%$yT0@X$%HTf-2Vyrd$hwHMKWHeyQ zFf|bk%Y-oXX)Bs@4O_nk-;B+$#WN|IECWi(HifBMTdZv?O~Y0AHez%LSIs0w|8Tus zdicE#Z27gp1}#Q_*3s%V)tar$yiN7NELzKoSLIQ&li!OeenZQOmVl83%iJ)Pb{m&A zRU`G8Pw3TGejy7oj6#zOJ_nBZy7KEsgWuuiqqr!*$HG7Z`~j@7!Av(L27IYuJ4i# zR%c{x;4xUuD~%^k&CWGv!y(FhJKaJ1A^Pn2*0$9tTh>{+fP|RO$b6+Y5?Q-wSLl~z z1@gU^hD6p8$z#M2)oHu6`uDHCHH`v8_2%h+J+u3XmihY`+2>>}JygX?x@CsxZvL*z z^uZoUmt{l4xO6&(MBIFJmWGQy4*M$oE>14#ULK~3bMz{N>VFZvwqDQo`j$!~)p#^5p(E9bo#e}Pl)51?y+-Nt`wyvFcl;7` za;8>RR&j$|yhbVaUDQ)3D~B@k>-WdjE7wcy4o8D)M8Ciwm&T)YpPsPl;q?;kr)0GC z_bcL8h9v z_1zc&cwhiAHte=Ov3rl#YxMV$(erbL?|81I&JrNcVvJW?exr%~p3!Zxn&)OqYc1r`f3hkWjqWgX<+}JzrBMSi-3eZWuFR!LZQ^9*A4BcT zo~&veCtN;RrMOPGWwMGUrei-brLXv0U~sjFA-*iC$_y?54?1H=wyn7mJT%PbfKze{ z8~cd+0u6WK)>(8cYD&i{U7Z@Ak;t%X_sy_=V8=qQw7hF`G50Cz)G@A;dhMgb$}vSv z+{cjRH$|U(RG*@5iQ(@qO=?ANf@V4lxBvCSq2g!ugnN9;ZqF$y-+l@SskmIzdMHbxL(Q zh->atYQaJ364&f@2%E==A>GFF#Y_C>*7&rT7)Ixa6US~uxxVGYmxX(2$ZlEP*mU?}N$oCJse)1!oX7ixbXDf~Me~dyl4sdBaUxiBCPV@EkjO+~qHl0Z~rivC< zTc{h3Br|cxJt|u==d3FC4GGy>I$y0Ju93c+!5q265&IttbjN<#vQPa~t*n0&hXP4X zjPxwS=PSRX#5H2X-&a$QQZN?UH;7W*Me5j5+Ik2z_w{jFJ%Njx%A$Zh8J(mdvS4(vmG}z(OgNJbo5-K@}0)!ur>N3&5=a4RK+Kq_glHa z#AOVV|Cwu4Gc+9Q4Gpi49|P(fbF_A9#2^tDo|n;o=lQ2C8#^Ue)~Iz7_jfeXqLDmZ z`KR;N^*QX+a9yjXyWb_YlJ8SXX{W?X^&Dl=QuT5AxVei>_YcU2XZ~F>68putHLGj1S4*zW{bXFnzW;gQ)8)-Zi}>^ zlBCS+@y;pPu~wZRuKhR~Qto^m($GqxBw42y zdrGnA**c7yHPR``v`&Rc+`?$2#`wO6lUAfjSLrXOMinFOk#~`q!O9r{)mX z-pz>XsD5JG!pU3uJ2kRzQ)kZN+yUEk7uw~KHg(epGY4B4#0trc7MJSVl=nH(Z-<8T zAhl=3#+F`i_KQCyF?&ciUrv6WcrEzN9*`^kV z^{;5iy`V7@KF^8Dmg<>PBTE!>awP9VXNCvOIrh~lDIcX`C2k8e$O>$|TYDFdcsnSAQ&MWX+9Porq9HXixI&e)5BKb672mYp3yE|Hnfljs zeHeBz(kYp=UAbK#XRD34Des*P$oJ{^C#S~Y?W!~yjt6LDz{a~0*&63~_9V=y@db(0 zNZCEv7iVAOGS?|tzF&)ZG1v!M?Q(;Uv!CBZ&A0514sL_5A;*{{%LJl?NvT;Lkx z9hx#EmK@yv#hm8(WVKeNV+?%>WAq`|cjb+b4bpTUZFC}ZEuJwd^dhNbMk57rll5sE zaq;#Sxs;Zt0MIZxBDLxwD>eCJ)E(3<`dIJvy)~3V%m#>7CPw*Pvd(h+__j<0NxG3_ ziMD52g^lPS7ccbU(oK(vQC}`mZL`pj*~o*NwGX#{kttL(^a1wK0b_1;{(1KPUELcY zG3GkP&7L3K4kBlwaT)8m59%|SkOKP`r9T!USLIS&XnZ%%+Uh}%gX)yT-A7!x;5*xJ z)tM@9=RY*=-7yPVe@K^jeC_CUW^ji*ST!!mjOMamJgRpO7kUS^85q6(1sZahLb{KS zs#-Lt{Xd(_YzN2x($w>@Ew}aOtk=f;uH{3!jE_2|o{QTYJf;#}Wt6XST(8TtQyaPU z9MS89Ru5WfA01F#u2R}MXvmx|?}XVdYqL&^LBm+eZfZ#O)M+1M`Ep)vF31#!va~y{ zb`#fr@R;sc3#wkKnq_YBSTy7Ul;=p4t2jn5}l^fhdn z6AW{rZp_{tiBIYM{^Ao=jucia#czz(nTAAWsb9Nq`*e3kVQ=TNNJ~zsCfBi@^{kpG z7eD@I)hgK^d{*7M&Pe_8tjc$T;|I>EiZ|Fdt{v2>8&3MbJ28%K?&MW_$C@nm% z-0x8>tIzAs-*@^KOMy?0jTTotTf6rXbzUuaj>Z8r&|&~=65t-qv?TWmgR4{4~_lfjZ-t>h3U6wzl<03QFi%n9}e}NKZa`u(^LSGbVP0c zN2{J?23c6rFeQ~Qs1V}Xe?dcLN()Z~^-EWVi6R zi+ad?Po)y0<#v}e%q$q0wX8m`O8?EJN{_qNIc8&i%TSAJsumftbh)NNX=F$LYkJ1! z*!xYd;`RKqv+hP1l2fiZ=WMfvU$wXv<^_sdP4)fpcV77x zB;!#lhV^*0WgmV=@58#j>RUeT=z0lgE9s{TleTfrnP-rG>X}WUdOfiQ+0PSOIvlSj zU;L^~=zWOT#+YiXXjtyvQMWjA9e<-~M|11LCk^j^SF@G8NT zfC{yp692m@-&0Cc4GpQq!71LXxOwj!*GOjE)^}AiG#o?GkjdJS?6+2IUv^BZE8Y4c zBw3IYsCTo-+3RJQ@tbjD?y7YX_dXgj^&PNiZq;9Zx*A8ra!0_?u_em zPkoY{l|VyUu|hr<-vw8%Hgjq;d#wDQ;kh>-t2xr)K7Fi@t+xu*?$2a?<8>zBQUUAYXaXe8ch-(i) zLzXe?yFDG&x>0}au?;;&G&M#$P0TW)X38-C>FQlR-cHHp zCn`kZomv1~;Jja{Nwb>#Znzu#w3RJkjo~Q8?mYz8je?Jc%V@xG^%-a*SXQ+ z0Ku~K>tcPWOY)X(T*UQgmLpDy*GsiWtmj8V+N8($C)@80x$NWADECsmenA)X=WBg- z9(cUYl|dESH|Cj6nFw(j?~YZaV@bc=8||Z4k(+n5yR&uILR?f73X;A;k{|1>Vuo#7 zKkZmjr{usJHD2PrLc zmvVoJjekFndigJX0DC|vHS>G1=FN`=h9uEymx;ck;QPN+C~+;e_xyx9w#;P<^Mn6g zXPizMKC-%UckTLK@5apM6-_5F8{8Pa96#_Os-f3M-Mez1ueG_$iLxu5!|CvkD(n@l zFcXb5ARKxa{cW9%t%ziC;p`^xB#((+fl8cW>A8wd)+wtMD9vtd#2CY3rUeDu6z2I$^sTp(De;JEEqcRGsJpQ87Hm96sR?U4glDThA{r*eO zEV`MQS4-8YFZ3?)OJdqLr+KE`_)Im3TD;)S5=$w&9eVro6d}9mcUH!KT7h=_00JHU(++~$1AVe_Vs%W8}FhlerC;v z{LUjqjPNqZo7s$)94GU%SGGWV>LmPh4PD3jso5*n^I6pj58wu@%uasLk`~XTYAjdN z_FPF_wE->R!`Er*C-CT_#nc{YE1pzEqY+UD4H+C#yH>gJHmdDnG?@3u#G*YCFC-0S zK8Q?dpSMDLd4+pn+-gE1J#(9@r8d>iAI$pJAdY0`$R0z|pjT|aMqfQ;Ey%c=cNvNF z!>z}rDK`1|<`zg~T`M!@UL%sZ*O3#ao@J;N>gP0zcme$rNQ%I&EM=h@01uY`8rNxHCr%%-lJv^#LYsnzwg8<3Yrvy~Vb~I$U zYToc&;scwnTyoRPMLC&6;eNT-k%ip3ItUpZiD47aJ z)A1S&>Gd0r$kM;a)^`WB)admcF4?!~<3Y(#%kB#=6W>N6s}7Xbc#O&NHJN&3wFNp- zxaq$!6xeC=n`5WjwbfG578<>gq{e#B>K*GhD>rzUW?h@L`n#!#4$?1&hRj!PWl5hp zX^9lFrb|g=-ujavd3!CJ=faiuOBrz~rSV)$M-2Q;YAMwMksA$Z$?vXW6Oz^;cUNtFtef8sc~s^X#ClOP}OsX~+B5Jq*YiAij!EoVK|k|Z`Cd&W-s<#hTZlakyV zwqZ3Hlb6Y;ga&EV9f{T$4b9G6j@V&5KZ*Zsah?c*WM-M28^(fpp~JZ@JOH;OyQSJiUU)9T#;+djKT+_%u@64)Ra=O1^ne_&Za%4I1;BEi%nhl(Qj|F5_ z3yRu2ZAEymH?!I;=60eir$mQ#mEQNgQ*5WEtUc^_Dzkc(oMK*1s!Gb!Tn{s=hAAkf z{&bhqC*NmQdx~KxsgLe?#eG){dE#b#z3r6ov-5 zDdD4EXlH}=v?H=BdhYy zOOdD{@2u*Myy|4UUgYSPRWI5_d-RRETMjHSlEdT1A(4zMN-<+c?{T|I8xqVf&8pVP zt4X}k6fSQvnPHq)lrnsK&53uaZWKU?*PeKf$+_LUQ6neL zO#DzD0b_MTnzSEfC`hE|gLCT zNr5iib0}|K&T@>(q4zDXB9GU~S;rH zXAZSM%pD_=%+Jp_p1Xz|_pEA|qgb~M$+aQ-ywaZf!(6wZ-l-k!Ju#!e|KrUv<5f2M zTWraVgcq$IJbgEEKy@t@T!9bi`KoTb>?SX^X^mjMyq3XN?UCdDzUoyOIiHOREb6OD zN@eRWw*}hE`RZp{-a0$x*YfROMYF7(CAECjczONp7tZhWICcj#<*aqDexgC~9=S$2 zOWMa*-SD(kcML~ED$r}#k(qlMuDow(P+N15h$DMk7+Y@7vg2}liat+zy`{b?G%eOQ zqakDS)pW`)b!3|dP7U+zy5Go$FHITr%{!0#syk^pp{^L|W{aqp`^|G7?NM0P4oNrG zSNWx*mA;}O^>@3=gW3MsZpOKRmLjJv8L+r!)#mF?$TV4UM$Kl*slteB_eDddIt`X> zomeE{G?1IHE~upEv`Q=d$@GUslG_uaKpMsnL=fI z??25Iy5^3|Jf<0vK}%v%U$c&r1wk3YDAk&rs=60B+k=Lb>Xlo%4(-l;tl`Yr$($-u zH2%*nt?qkqmKn~YGNfljFkX=~+u!mgmzrqDAM~!q%d$SVnulMQuSwc>=GM;y&+)%z z`EvCnSM6Fo(Z*TwsOREAdGfeww_cOoEB36~lu5}o4Q)bNERXWZKyCckPpT1DJZQnp zq>jux#=dk~kJI%TZ*1Cs+^BJs&Au!)1BEq?tIQdxhJU;qY8Kb5j{n*>tHtPvRB5{{ z$fA3BT5CZUvli#%Q>C-gVKcQedzbiqRuLDoM>O9QHM&F_U6RpM_C)#h+1`=zdrwDA zC>i3c(>O)dI|(f@qZszq#7jke4*2VJ{(ZkJYePKa_G_Q~>JzWO+J~Yce(yIUOYUc7 zvNFFm{eE_SH`?-pj4GE`**$&i+_C~L{ZxmaGoah32-L(6? z)r7$n9!lSAl+o-Z&D!`chcUfg8(>XOumq@1K5yLh8(wdk(qWp^vB-yYtyKH-!L0Tss>jX^UR`T1US>2J+! zn(kOTvp)tWiVn`PBU=5N!KZv&J$DE@e0GEZFXIrT8glxbE! z^SmsEdHave{&(bm<<)#4+)T`@MYEu1d~t{GRH^CuMz^QxYNW74WsP&xisWr zrc-_{a(}M`rkD=%hnpAv9QI($>kxTrL{^*VA)l0Tm2ZtjzT5xvpDRXZ zd92;y)F!aWORG?SI+~!;uJRSK$Xji12d8gdyMj}rF%ntjYEn_vj&-lv)F}xst=16N zz8H~`eKQ*j7GG8mdu5<0vPK}ghT;+qhkrO7oE)x8x zPkE=rQAYU%5Vt8BTpUN1UUKYlmr_S_IWPEo>ub(ODlx!-a!ia0Xf<`Vh z?wwnmyv3cgRh=3xWz`0;p1Z7G?va)ks|M|f)t)}q^Ij8)+*vPN^Y_%XRwRyc#_d*C zeUZ3R(2#Ps+cT?qzf_fiof`IX#$@u`gM1%P_uHzq1XINTmjUHe^*|;cBg&~r2~(9< zTLNuuEY=#zUXcA)HB_yF*#62Qn@o;9-8b&)KcUMEt$Wv=Rr^#!zwAvEGN5m_+_7aX zuH2B-B>EawTJJy?j}TYw35rQkF){7428?v-1ca!3g>lPTA<93PQ{qrzTWVW3)KjVM z4x4AvL2Sy()6%4>Xb}0i9HP1ep&u`v0)k=5ewob375=2_Ra`fnZN@z|)*`jC5~Hj` z*X+WY;J0iWi&ka|YQKXs{*b%6g_8Zpt7`u&<+oNa&Deij=l`yUZ+S6{+P}M`C<|aN zMkD;7GAGhLNsHEXm0yyIJX=?73g%+bqn>h4e;2 z=B#5{P2ITr+EH19H728e^;A$1=DP#YNQ1^nw;C53Z+)3tyC6jx)rq+FZ4LFfm6vu|cO`SeM4ARK&X_A)tVwH&SK9n5x}myI zl+2$Zl9;u>k4&~@@0vkGGM=uyfkcY+G~ub=)1?WM4`s*&Cl{;ZYN+DH@a2~cRX17V z`h=z|&yC4@Hp7xaHRT0B(WIE>3az;s_T7oKwi=eCk$PQ>wcf0a^#0>JBh|!mr1b!~ zxNty%P5YkwGW;fKNuM0ZEB*R1p4(-6&2I=<&QPU7INP671`h zvYa|uG+r9zuXnwFuDteOE}k|KN1Vne zzkNUZQpXiI^ldU7ug;8B6>VMAoCTZp@&l*;c7+gUO7(+joLM?EQ9VYW zrA9L~wY)9z`+bDAg#2@J=J zh-K5F23NA#JXF{rTiT4R`?T)Tt99r0y?V9oQLsnrmV9TgSI_)CTQ=|1TD|<))>@5g zVwe@^5O(l~7p@+j6FC)w*T-&doddb?BMDQ~S2<)THLNOv9DPc zuDGY2Ev0JN#FkxkizMF0fi}Lm)|x*p+u9~XRqbFqW>Iz9*)pm;eQaJ)6FS>6xkud_ zXlt4{D!~YwPl{wM+IK0?t7p&FJ^Hj(3o|6Nt74sP#g$K}Em2g3X|_yR)#jEqdsMS1 zo846{2qkH^R<;Hza+57})Y$E|8_CtH-L|Ar>5tfg>Zpya`I_0Hy(D(KjV+Zb*p_T) Mmbzw0IDOjx1N!F}$p8QV diff --git a/package.json b/package.json index d21e929f..a6d06d6d 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "embla-carousel-react": "^8.6.0", "extract-zip": "^2.0.1", "form-data": "^4.0.2", - "framer-motion": "^12.23.5", + "framer-motion": "^12.38.0", "get-port": "^7.1.0", "iron-session": "^8.0.4", "jose": "^6.1.0", @@ -100,7 +100,7 @@ "react-transition-group": "^4.4.5", "react-zoom-pan-pinch": "^3.7.0", "readdirp": "^4.1.1", - "recharts": "^2.15.3", + "recharts": "^3.8.0", "sharp": "^0.34.3", "swr": "^2.3.2", "uuid": "^11.1.0", diff --git a/src/app/darmasaba/_com/main-page/apbdes/components/apbdesSkeleton.tsx b/src/app/darmasaba/_com/main-page/apbdes/components/apbdesSkeleton.tsx new file mode 100644 index 00000000..7608474b --- /dev/null +++ b/src/app/darmasaba/_com/main-page/apbdes/components/apbdesSkeleton.tsx @@ -0,0 +1,117 @@ +import { Skeleton, Stack, Box, Group } from '@mantine/core' + +export function PaguTableSkeleton() { + return ( + + + + {/* Header */} + + + + + + {/* Section headers */} + + + + + + + + + + + + + + ) +} + +export function RealisasiTableSkeleton() { + return ( + + + + {/* Header */} + + + + + + + {/* Rows */} + {[1, 2, 3, 4, 5].map((i) => ( + + + + + + ))} + + + ) +} + +export function GrafikRealisasiSkeleton() { + return ( + + + + {[1, 2, 3].map((i) => ( + + + + + + + + + + ))} + + + ) +} + +export function SummaryCardsSkeleton() { + return ( + + + {[1, 2, 3].map((i) => ( + + + + + + + + + + ))} + + ) +} + +export function ApbdesMainSkeleton() { + return ( + + {/* Title */} + + + + {/* Select */} + + + {/* Summary Cards */} + + + {/* Tables and Charts */} + + + + + + + ) +} diff --git a/src/app/darmasaba/_com/main-page/apbdes/index.tsx b/src/app/darmasaba/_com/main-page/apbdes/index.tsx index bf0f9748..62134cd0 100644 --- a/src/app/darmasaba/_com/main-page/apbdes/index.tsx +++ b/src/app/darmasaba/_com/main-page/apbdes/index.tsx @@ -1,7 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' -import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes' + +import apbdesState from '@/app/admin/(dashboard)/_state/landing-page/apbdes' import colors from '@/con/colors' import { Box, @@ -12,30 +13,43 @@ import { SimpleGrid, Stack, Text, - Title + Title, + LoadingOverlay, + Transition, } from '@mantine/core' +import { motion } from 'framer-motion' import Link from 'next/link' import { useEffect, useState } from 'react' import { useProxy } from 'valtio/utils' + +import { ApbdesMainSkeleton } from './components/apbdesSkeleton' +import ComparisonChart from './lib/comparisonChart' import GrafikRealisasi from './lib/grafikRealisasi' import PaguTable from './lib/paguTable' import RealisasiTable from './lib/realisasiTable' +const MotionStack = motion.create(Stack) + function Apbdes() { - const state = useProxy(apbdes) + const state = useProxy(apbdesState) const [selectedYear, setSelectedYear] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const [isChangingYear, setIsChangingYear] = useState(false) const textHeading = { title: 'APBDes', - des: 'Transparansi APBDes Darmasaba adalah langkah nyata menuju tata kelola desa yang bersih, terbuka, dan bertanggung jawab.' + des: 'Transparansi APBDes Darmasaba adalah langkah nyata menuju tata kelola desa yang bersih, terbuka, dan bertanggung jawab.', } useEffect(() => { const loadData = async () => { try { + setIsLoading(true) await state.findMany.load() } catch (error) { console.error('Error loading data:', error) + } finally { + setIsLoading(false) } } loadData() @@ -51,7 +65,7 @@ function Apbdes() { ) ) .sort((a, b) => b - a) - .map(year => ({ + .map((year) => ({ value: year.toString(), label: `Tahun ${year}`, })) @@ -60,168 +74,190 @@ function Apbdes() { if (years.length > 0 && !selectedYear) { setSelectedYear(years[0].value) } - }, [years, selectedYear]) + }, [years]) const currentApbdes = dataAPBDes.length > 0 - ? dataAPBDes.find((item: any) => item?.tahun?.toString() === selectedYear) || dataAPBDes[0] + ? (dataAPBDes.find((item: any) => item?.tahun?.toString() === selectedYear) || dataAPBDes[0]) : null - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const previewData = (state.findMany.data || []).slice(0, 3) + const handleYearChange = (value: string | null) => { + if (value !== selectedYear) { + setIsChangingYear(true) + setSelectedYear(value) + setTimeout(() => setIsChangingYear(false), 500) + } + } return ( - - - {/* ๐Ÿ“Œ HEADING */} - - - + <LoadingOverlay + visible={isLoading} + zIndex={1000} + overlayProps={{ radius: 'sm', blur: 2 }} + loaderProps={{ color: colors['blue-button'], type: 'dots' }} + /> + + <Transition mounted={!isLoading} transition="fade" duration={600}> + {(styles) => ( + <MotionStack + style={styles} + gap="xl" > - {textHeading.title} - - - - {textHeading.des} - - - - - {/* Button Lihat Semua */} - - - - - {/* COMBOBOX */} - - Pilih Tahun APBDes} + placeholder="Pilih tahun" + value={selectedYear} + onChange={handleYearChange} + data={years} + w={{ base: '100%', sm: 220 }} + searchable + clearable + nothingFoundMessage="Tidak ada tahun tersedia" + disabled={isChangingYear} + /> + + + {/* Tables & Charts */} + {currentApbdes && currentApbdes.items && currentApbdes.items.length > 0 ? ( + + + {(styles) => ( + + + + + + + + + + + + + + )} + + + {/* Comparison Chart */} + + + {(styles) => ( + + + + )} + + + + ) : currentApbdes ? ( + + + ๐Ÿ“Š + + Tidak ada data item untuk tahun yang dipilih. + + + + ) : null} + + {/* Loading State for Year Change */} + + {(styles) => ( + + + + )} + + + )} + ) } -export default Apbdes \ No newline at end of file +export default Apbdes diff --git a/src/app/darmasaba/_com/main-page/apbdes/lib/comparisonChart.tsx b/src/app/darmasaba/_com/main-page/apbdes/lib/comparisonChart.tsx new file mode 100644 index 00000000..0b03fed0 --- /dev/null +++ b/src/app/darmasaba/_com/main-page/apbdes/lib/comparisonChart.tsx @@ -0,0 +1,229 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Paper, Title, Box, Text, Stack, Group, rem } from '@mantine/core' +import { + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, + Cell, +} from 'recharts' +import { APBDes, APBDesItem } from '../types/apbdes' + +interface ComparisonChartProps { + apbdesData: APBDes +} + +export default function ComparisonChart({ apbdesData }: ComparisonChartProps) { + const items = apbdesData?.items || [] + const tahun = apbdesData?.tahun || new Date().getFullYear() + + const pendapatan = items.filter((i: APBDesItem) => i.tipe === 'pendapatan') + const belanja = items.filter((i: APBDesItem) => i.tipe === 'belanja') + const pembiayaan = items.filter((i: APBDesItem) => i.tipe === 'pembiayaan') + + const totalPendapatan = pendapatan.reduce((sum, i) => sum + i.anggaran, 0) + const totalBelanja = belanja.reduce((sum, i) => sum + i.anggaran, 0) + const totalPembiayaan = pembiayaan.reduce((sum, i) => sum + i.anggaran, 0) + + // Hitung total realisasi dari realisasiItems (konsisten dengan RealisasiTable) + const totalPendapatanRealisasi = pendapatan.reduce( + (sum, i) => { + if (i.realisasiItems && i.realisasiItems.length > 0) { + return sum + i.realisasiItems.reduce((sumReal, real) => sumReal + (real.jumlah || 0), 0) + } + return sum + }, + 0 + ) + const totalBelanjaRealisasi = belanja.reduce( + (sum, i) => { + if (i.realisasiItems && i.realisasiItems.length > 0) { + return sum + i.realisasiItems.reduce((sumReal, real) => sumReal + (real.jumlah || 0), 0) + } + return sum + }, + 0 + ) + const totalPembiayaanRealisasi = pembiayaan.reduce( + (sum, i) => { + if (i.realisasiItems && i.realisasiItems.length > 0) { + return sum + i.realisasiItems.reduce((sumReal, real) => sumReal + (real.jumlah || 0), 0) + } + return sum + }, + 0 + ) + + const formatRupiah = (value: number) => { + if (value >= 1000000000) { + return `Rp ${(value / 1000000000).toFixed(1)}B` + } + if (value >= 1000000) { + return `Rp ${(value / 1000000).toFixed(1)}Jt` + } + if (value >= 1000) { + return `Rp ${(value / 1000).toFixed(0)}Rb` + } + return `Rp ${value.toFixed(0)}` + } + + const data = [ + { + name: 'Pendapatan', + pagu: totalPendapatan, + realisasi: totalPendapatanRealisasi, + fill: '#40c057', + }, + { + name: 'Belanja', + pagu: totalBelanja, + realisasi: totalBelanjaRealisasi, + fill: '#fa5252', + }, + { + name: 'Pembiayaan', + pagu: totalPembiayaan, + realisasi: totalPembiayaanRealisasi, + fill: '#fd7e14', + }, + ] + + const CustomTooltip = ({ active, payload }: any) => { + if (active && payload && payload.length) { + const data = payload[0].payload + return ( + + + + {data.name} + + + + Pagu: + + + {formatRupiah(data.pagu)} + + + + + Realisasi: + + + {formatRupiah(data.realisasi)} + + + {data.pagu > 0 && ( + + + Persentase: + + = data.pagu ? 'teal' : 'blue'} + > + {((data.realisasi / data.pagu) * 100).toFixed(1)}% + + + )} + + + ) + } + return null + } + + return ( + + + Perbandingan Pagu vs Realisasi {tahun} + + + + + + + + + } /> + + + {data.map((entry, index) => ( + + ))} + + + + + + + + + *Geser cursor pada bar untuk melihat detail + + + + ) +} diff --git a/src/app/darmasaba/_com/main-page/apbdes/lib/grafikRealisasi.tsx b/src/app/darmasaba/_com/main-page/apbdes/lib/grafikRealisasi.tsx index fe1b8909..07bdb183 100644 --- a/src/app/darmasaba/_com/main-page/apbdes/lib/grafikRealisasi.tsx +++ b/src/app/darmasaba/_com/main-page/apbdes/lib/grafikRealisasi.tsx @@ -1,125 +1,224 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Paper, Title, Progress, Stack, Text, Group, Box } from '@mantine/core'; - -interface APBDesItem { - tipe: string | null; - anggaran: number; - realisasi?: number; - totalRealisasi?: number; -} +import { Paper, Title, Progress, Stack, Text, Group, Box, rem } from '@mantine/core' +import { IconArrowUpRight, IconArrowDownRight } from '@tabler/icons-react' +import { APBDes, APBDesItem, SummaryData } from '../types/apbdes' interface SummaryProps { - title: string; - data: APBDesItem[]; + title: string + data: APBDesItem[] + icon?: React.ReactNode } -function Summary({ title, data }: SummaryProps) { - if (!data || data.length === 0) return null; +function Summary({ title, data, icon }: SummaryProps) { + if (!data || data.length === 0) return null - const totalAnggaran = data.reduce((s: number, i: APBDesItem) => s + i.anggaran, 0); - // Use realisasi field (already mapped from totalRealisasi in transformAPBDesData) - const totalRealisasi = data.reduce( - (s: number, i: APBDesItem) => s + (i.realisasi || i.totalRealisasi || 0), - 0 - ); + const totalAnggaran = data.reduce((sum, i) => sum + i.anggaran, 0) + + // Hitung total realisasi dari realisasiItems (konsisten dengan RealisasiTable) + const totalRealisasi = data.reduce((sum, i) => { + if (i.realisasiItems && i.realisasiItems.length > 0) { + return sum + i.realisasiItems.reduce((sumReal, real) => sumReal + (real.jumlah || 0), 0) + } + return sum + }, 0) - const persen = - totalAnggaran > 0 ? (totalRealisasi / totalAnggaran) * 100 : 0; + const persentase = totalAnggaran > 0 ? (totalRealisasi / totalAnggaran) * 100 : 0 - // Format angka ke dalam format Rupiah const formatRupiah = (angka: number) => { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, maximumFractionDigits: 0, - }).format(angka); - }; + }).format(angka) + } - // Tentukan warna berdasarkan persentase const getProgressColor = (persen: number) => { - if (persen >= 100) return 'teal'; - if (persen >= 80) return 'blue'; - if (persen >= 60) return 'yellow'; - return 'red'; - }; + if (persen >= 100) return 'teal' + if (persen >= 80) return 'blue' + if (persen >= 60) return 'yellow' + return 'red' + } + + const getStatusMessage = (persen: number) => { + if (persen >= 100) { + return { text: 'Realisasi mencapai 100% dari anggaran', color: 'teal' } + } + if (persen >= 80) { + return { text: 'Realisasi baik, mendekati target', color: 'blue' } + } + if (persen >= 60) { + return { text: 'Realisasi cukup, perlu ditingkatkan', color: 'yellow' } + } + return { text: 'Realisasi rendah, perlu perhatian khusus', color: 'red' } + } + + const statusMessage = getStatusMessage(persentase) return ( - {title} - - {persen.toFixed(2)}% - + + {icon} + {title} + + + {persentase >= 100 ? ( + + ) : persentase < 60 ? ( + + ) : null} + + {persentase.toFixed(1)}% + + - - Realisasi: {formatRupiah(totalRealisasi)} / Anggaran: {formatRupiah(totalAnggaran)} + + Realisasi: {formatRupiah(totalRealisasi)} + {' '}/ Anggaran: {formatRupiah(totalAnggaran)} - {persen >= 100 && ( - - โœ“ Realisasi mencapai 100% dari anggaran - - )} - - {persen < 100 && persen >= 80 && ( - - โšก Realisasi baik, mendekati target - - )} - - {persen < 80 && persen >= 60 && ( - - โš ๏ธ Realisasi cukup, perlu ditingkatkan - - )} - - {persen < 60 && ( - - โš ๏ธ Realisasi rendah, perlu perhatian khusus - - )} + + {persentase >= 100 && 'โœ“ '}{statusMessage.text} + - ); + ) } -export default function GrafikRealisasi({ - apbdesData, -}: { - apbdesData: { - tahun?: number | null; - items?: APBDesItem[] | null; - [key: string]: any; - }; -}) { - const items = apbdesData?.items || []; - const tahun = apbdesData?.tahun || new Date().getFullYear(); +interface GrafikRealisasiProps { + apbdesData: APBDes +} - const pendapatan = items.filter((i: APBDesItem) => i.tipe === 'pendapatan'); - const belanja = items.filter((i: APBDesItem) => i.tipe === 'belanja'); - const pembiayaan = items.filter((i: APBDesItem) => i.tipe === 'pembiayaan'); +export default function GrafikRealisasi({ apbdesData }: GrafikRealisasiProps) { + const items = apbdesData?.items || [] + const tahun = apbdesData?.tahun || new Date().getFullYear() + + const pendapatan = items.filter((i: APBDesItem) => i.tipe === 'pendapatan') + const belanja = items.filter((i: APBDesItem) => i.tipe === 'belanja') + const pembiayaan = items.filter((i: APBDesItem) => i.tipe === 'pembiayaan') return ( - - + <Paper + withBorder + p="lg" + radius="lg" + shadow="sm" + style={{ + transition: 'box-shadow 0.3s ease', + ':hover': { + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)', + }, + }} + h={"100%"} + > + <Title + order={5} + mb="lg" + c="blue.9" + fz={{ base: '1rem', md: '1.1rem' }} + fw={700} + > GRAFIK REALISASI APBDes {tahun} - - - - + + + ๐Ÿ’ฐ + + } + /> + + + ๐Ÿ’ธ + + } + /> + + + ๐Ÿ“Š + + } + /> - ); -} \ No newline at end of file + ) +} diff --git a/src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx b/src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx index 2df04199..04794c4c 100644 --- a/src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx +++ b/src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx @@ -1,60 +1,180 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Paper, Table, Title } from '@mantine/core'; +import { Paper, Table, Title, Box, ScrollArea, Badge } from '@mantine/core' +import { APBDes, APBDesItem } from '../types/apbdes' -function Section({ title, data }: any) { - if (!data || data.length === 0) return null; +interface SectionProps { + title: string + data: APBDesItem[] + badgeColor?: string +} + +function Section({ title, data, badgeColor = 'blue' }: SectionProps) { + if (!data || data.length === 0) return null return ( <> - + - {title} + + {title} + - {data.map((item: any) => ( - - - {item.kode} - {item.uraian} + {data.map((item, index) => ( + + + + + {item.kode} + + + {item.uraian} + + - + Rp {item.anggaran.toLocaleString('id-ID')} ))} - ); + ) } -export default function PaguTable({ apbdesData }: any) { - const items = apbdesData.items || []; +interface PaguTableProps { + apbdesData: APBDes +} - const title = - apbdesData.tahun - ? `PAGU APBDes Tahun ${apbdesData.tahun}` - : 'PAGU APBDes'; +export default function PaguTable({ apbdesData }: PaguTableProps) { + const items = apbdesData.items || [] - const pendapatan = items.filter((i: any) => i.tipe === 'pendapatan'); - const belanja = items.filter((i: any) => i.tipe === 'belanja'); - const pembiayaan = items.filter((i: any) => i.tipe === 'pembiayaan'); + const title = apbdesData.tahun + ? `PAGU APBDes Tahun ${apbdesData.tahun}` + : 'PAGU APBDes' + + const pendapatan = items.filter((i: APBDesItem) => i.tipe === 'pendapatan') + const belanja = items.filter((i: APBDesItem) => i.tipe === 'belanja') + const pembiayaan = items.filter((i: APBDesItem) => i.tipe === 'pembiayaan') + + // Calculate totals + const totalPendapatan = pendapatan.reduce((sum, i) => sum + i.anggaran, 0) + const totalBelanja = belanja.reduce((sum, i) => sum + i.anggaran, 0) + const totalPembiayaan = pembiayaan.reduce((sum, i) => sum + i.anggaran, 0) return ( - - {title} + + + {title} + - - - - Uraian - Anggaran (Rp) - - - -
-
-
- -
+ + + + + + Uraian + + + Anggaran (Rp) + + + + +
+ {totalPendapatan > 0 && ( + + Total Pendapatan + + Rp {totalPendapatan.toLocaleString('id-ID')} + + + )} + +
+ {totalBelanja > 0 && ( + + Total Belanja + + Rp {totalBelanja.toLocaleString('id-ID')} + + + )} + +
+ {totalPembiayaan > 0 && ( + + Total Pembiayaan + + Rp {totalPembiayaan.toLocaleString('id-ID')} + + + )} + +
+
- ); -} \ No newline at end of file + ) +} diff --git a/src/app/darmasaba/_com/main-page/apbdes/lib/realisasiTable.tsx b/src/app/darmasaba/_com/main-page/apbdes/lib/realisasiTable.tsx index 889429c8..7aea80f5 100644 --- a/src/app/darmasaba/_com/main-page/apbdes/lib/realisasiTable.tsx +++ b/src/app/darmasaba/_com/main-page/apbdes/lib/realisasiTable.tsx @@ -1,86 +1,212 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Paper, Table, Title, Badge, Text } from '@mantine/core'; +import { Paper, Table, Title, Badge, Text, Box, ScrollArea } from '@mantine/core' +import { APBDes, APBDesItem, RealisasiItem } from '../types/apbdes' -export default function RealisasiTable({ apbdesData }: any) { - const items = apbdesData.items || []; +interface RealisasiRowProps { + realisasi: RealisasiItem + parentItem: APBDesItem +} - const title = - apbdesData.tahun - ? `REALISASI APBDes Tahun ${apbdesData.tahun}` - : 'REALISASI APBDes'; +function RealisasiRow({ realisasi, parentItem }: RealisasiRowProps) { + const persentase = parentItem.anggaran > 0 + ? (realisasi.jumlah / parentItem.anggaran) * 100 + : 0 - // Flatten: kumpulkan semua realisasi items - const allRealisasiRows: Array<{ realisasi: any; parentItem: any }> = []; - - items.forEach((item: any) => { - if (item.realisasiItems && item.realisasiItems.length > 0) { - item.realisasiItems.forEach((realisasi: any) => { - allRealisasiRows.push({ realisasi, parentItem: item }); - }); - } - }); + const getBadgeColor = (percentage: number) => { + if (percentage >= 100) return 'teal' + if (percentage >= 80) return 'blue' + if (percentage >= 60) return 'yellow' + return 'red' + } - const formatRupiah = (amount: number) => { - return new Intl.NumberFormat('id-ID', { - style: 'currency', - currency: 'IDR', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(amount); - }; + const getBadgeVariant = (percentage: number) => { + if (percentage >= 100) return 'filled' + return 'light' + } return ( - - {title} + + + + + {realisasi.kode || '-'} + + + {realisasi.keterangan || '-'} + + + + + {new Intl.NumberFormat('id-ID', { + style: 'currency', + currency: 'IDR', + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(realisasi.jumlah || 0)} + + + + {persentase.toFixed(1)}% + + + + ) +} + +interface RealisasiTableProps { + apbdesData: APBDes +} + +export default function RealisasiTable({ apbdesData }: RealisasiTableProps) { + const items = apbdesData.items || [] + + const title = apbdesData.tahun + ? `REALISASI APBDes Tahun ${apbdesData.tahun}` + : 'REALISASI APBDes' + + // Flatten: kumpulkan semua realisasi items + const allRealisasiRows: Array<{ realisasi: RealisasiItem; parentItem: APBDesItem }> = [] + + items.forEach((item: APBDesItem) => { + if (item.realisasiItems && item.realisasiItems.length > 0) { + item.realisasiItems.forEach((realisasi: RealisasiItem) => { + allRealisasiRows.push({ realisasi, parentItem: item }) + }) + } + }) + + // Calculate total realisasi + const totalRealisasi = allRealisasiRows.reduce( + (sum, { realisasi }) => sum + (realisasi.jumlah || 0), + 0 + ) + + return ( + + + {title} + {allRealisasiRows.length === 0 ? ( - - Belum ada data realisasi - + + + Belum ada data realisasi untuk tahun ini + + ) : ( - - - - Uraian - Realisasi (Rp) - % - - - - {allRealisasiRows.map(({ realisasi, parentItem }) => { - const persentase = parentItem.anggaran > 0 - ? (realisasi.jumlah / parentItem.anggaran) * 100 - : 0; - - return ( - - - {realisasi.kode || '-'} - {realisasi.keterangan || '-'} - - - - {formatRupiah(realisasi.jumlah || 0)} - - - - = 100 - ? 'teal' - : persentase >= 60 - ? 'yellow' - : 'red' - } - > - {persentase.toFixed(2)}% - - + <> + +
+ + + Uraian + Realisasi (Rp) + % - ); - })} - -
+ + + {allRealisasiRows.map(({ realisasi, parentItem }) => ( + + ))} + + + + + + Total Realisasi:{' '} + + {new Intl.NumberFormat('id-ID', { + style: 'currency', + currency: 'IDR', + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(totalRealisasi)} + + + + )}
- ); -} \ No newline at end of file + ) +} diff --git a/src/app/darmasaba/_com/main-page/apbdes/types/apbdes.ts b/src/app/darmasaba/_com/main-page/apbdes/types/apbdes.ts new file mode 100644 index 00000000..279abe05 --- /dev/null +++ b/src/app/darmasaba/_com/main-page/apbdes/types/apbdes.ts @@ -0,0 +1,90 @@ +// Types for APBDes data structure + +export interface APBDesItem { + id?: string; + kode: string; + uraian: string; + deskripsi?: string; + tipe: 'pendapatan' | 'belanja' | 'pembiayaan' | null; + anggaran: number; + level?: number; + // Calculated fields + realisasi?: number; + selisih?: number; + persentase?: number; + // Realisasi items (nested) + realisasiItems?: RealisasiItem[]; + createdAt?: string | Date; + updatedAt?: string | Date; +} + +export interface RealisasiItem { + id: string; + kode: string; + keterangan?: string; + jumlah: number; + tanggal?: string | Date; + apbDesItemId: string; + buktiFileId?: string; + createdAt?: string | Date; + updatedAt?: string | Date; +} + +export interface APBDes { + id: string; + name?: string | null; + tahun: number; + jumlah: number; + deskripsi?: string | null; + items?: APBDesItem[]; + image?: { + id: string; + link: string; + name?: string; + path?: string; + } | null; + file?: { + id: string; + link: string; + name?: string; + } | null; + imageId?: string; + fileId?: string; + createdAt?: string | Date; + updatedAt?: string | Date; +} + +export interface APBDesResponse { + id: string; + tahun: number; + name?: string | null; + jumlah: number; + items?: APBDesItem[]; + image?: { + id: string; + link: string; + } | null; + file?: { + id: string; + link: string; + } | null; +} + +export interface SummaryData { + title: string; + totalAnggaran: number; + totalRealisasi: number; + persentase: number; +} + +export interface FilterState { + search: string; + tipe: 'all' | 'pendapatan' | 'belanja' | 'pembiayaan'; + sortBy: 'uraian' | 'anggaran' | 'realisasi' | 'persentase'; + sortOrder: 'asc' | 'desc'; +} + +export type LoadingState = { + initial: boolean; + changingYear: boolean; +}; diff --git a/task-project-apbdes.md b/task-project-apbdes.md new file mode 100644 index 00000000..677e4979 --- /dev/null +++ b/task-project-apbdes.md @@ -0,0 +1,418 @@ +# Task Project Menu: Modernisasi Halaman APBDes + +## ๐Ÿ“Š Project Overview + +**Target File**: `src/app/darmasaba/_com/main-page/apbdes/index.tsx` + +**Goal**: Modernisasi tampilan dan fungsionalitas halaman APBDes untuk meningkatkan user experience, visualisasi data, dan code quality. + +--- + +## ๐ŸŽฏ Task List + +### **Phase 1: UI/UX Enhancement** ๐Ÿ”ฅ HIGH PRIORITY + +#### Task 1.1: Add Loading State +- [ ] Create `apbdesSkeleton.tsx` component +- [ ] Add skeleton untuk PaguTable +- [ ] Add skeleton untuk RealisasiTable +- [ ] Add skeleton untuk GrafikRealisasi +- [ ] Implement loading state saat ganti tahun +- [ ] Add smooth fade-in transition saat data load + +**Files to Create/Modify**: +- `src/app/darmasaba/_com/main-page/apbdes/components/apbdesSkeleton.tsx` (CREATE) +- `src/app/darmasaba/_com/main-page/apbdes/index.tsx` (MODIFY) + +**Estimated Time**: 45 menit + +--- + +#### Task 1.2: Improve Table Design +- [ ] Add hover effects pada table rows +- [ ] Implement striped rows untuk readability +- [ ] Add sticky header untuk long data +- [ ] Improve typography dan spacing +- [ ] Add responsive table wrapper untuk mobile +- [ ] Add color coding untuk tipe data berbeda + +**Files to Modify**: +- `src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx` +- `src/app/darmasaba/_com/main-page/apbdes/lib/realisasiTable.tsx` + +**Estimated Time**: 1 jam + +--- + +#### Task 1.3: Add Animations & Interactions +- [ ] Install Framer Motion (`bun add framer-motion`) +- [ ] Add fade-in animation untuk main container +- [ ] Add slide-up animation untuk tables +- [ ] Add hover scale effect untuk cards +- [ ] Add smooth transition saat ganti tahun +- [ ] Add loading spinner untuk Select component + +**Dependencies**: `framer-motion` + +**Files to Modify**: +- `src/app/darmasaba/_com/main-page/apbdes/index.tsx` +- `src/app/darmasaba/_com/main-page/apbdes/lib/*.tsx` + +**Estimated Time**: 1 jam + +--- + +### **Phase 2: Data Visualization** ๐Ÿ“ˆ HIGH PRIORITY + +#### Task 2.1: Install & Setup Recharts +- [ ] Install Recharts (`bun add recharts`) +- [ ] Create basic bar chart component +- [ ] Add tooltip dengan formatted data +- [ ] Add responsive container +- [ ] Configure color scheme + +**Dependencies**: `recharts` + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/lib/comparisonChart.tsx` (CREATE) + +**Estimated Time**: 1 jam + +--- + +#### Task 2.2: Create Interactive Charts +- [ ] Bar chart: Pagu vs Realisasi comparison +- [ ] Pie chart: Komposisi per kategori +- [ ] Line chart: Trend multi-tahun (jika data tersedia) +- [ ] Add legend dan labels +- [ ] Add export chart as image feature + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/lib/barChart.tsx` (CREATE) +- `src/app/darmasaba/_com/main-page/apbdes/lib/pieChart.tsx` (CREATE) + +**Estimated Time**: 2 jam + +--- + +#### Task 2.3: Create Summary Cards +- [ ] Design summary card component +- [ ] Display Total Pagu +- [ ] Display Total Realisasi +- [ ] Display Persentase Realisasi +- [ ] Add trend indicators (โ†‘โ†“) +- [ ] Add color-coded performance badges +- [ ] Add animated number counters + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/lib/summaryCards.tsx` (CREATE) + +**Estimated Time**: 1.5 jam + +--- + +### **Phase 3: Features** โš™๏ธ MEDIUM PRIORITY + +#### Task 3.1: Search & Filter +- [ ] Add search input untuk filter items +- [ ] Add filter dropdown by tipe (Pendapatan/Belanja/Pembiayaan) +- [ ] Add sort functionality (by jumlah, realisasi, persentase) +- [ ] Add clear filter button +- [ ] Add search result counter + +**Files to Create/Modify**: +- `src/app/darmasaba/_com/main-page/apbdes/hooks/useApbdesFilter.ts` (CREATE) +- `src/app/darmasaba/_com/main-page/apbdes/index.tsx` (MODIFY) + +**Estimated Time**: 1.5 jam + +--- + +#### Task 3.2: Export & Print Functionality +- [ ] Install PDF library (`bun add @react-pdf/renderer`) +- [ ] Create PDF export template +- [ ] Add Excel export (`bun add exceljs`) +- [ ] Add print CSS styles +- [ ] Create export buttons component +- [ ] Add loading state saat export + +**Dependencies**: `@react-pdf/renderer`, `exceljs` + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/components/exportButtons.tsx` (CREATE) +- `src/app/darmasaba/_com/main-page/apbdes/utils/exportPdf.ts` (CREATE) +- `src/app/darmasaba/_com/main-page/apbdes/utils/exportExcel.ts` (CREATE) + +**Estimated Time**: 2 jam + +--- + +#### Task 3.3: Detail View Modal +- [ ] Add modal component untuk detail item +- [ ] Display breakdown realisasi per item +- [ ] Add historical comparison (tahun sebelumnya) +- [ ] Add close button dan ESC key handler +- [ ] Add responsive modal design + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/components/detailModal.tsx` (CREATE) + +**Estimated Time**: 1.5 jam + +--- + +### **Phase 4: Code Quality** ๐Ÿงน MEDIUM PRIORITY + +#### Task 4.1: TypeScript Improvements +- [ ] Create proper TypeScript types +- [ ] Replace all `any` dengan interfaces +- [ ] Add Zod schema validation +- [ ] Type-safe API responses +- [ ] Add generic types untuk reusable components + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/types/apbdes.ts` (CREATE) + +**Files to Modify**: +- All `.tsx` files in apbdes directory + +**Estimated Time**: 1.5 jam + +--- + +#### Task 4.2: Code Cleanup +- [ ] Remove all commented code +- [ ] Remove console.logs (replace dengan proper logging) +- [ ] Add error boundaries +- [ ] Improve error messages +- [ ] Add proper ESLint comments +- [ ] Add JSDoc untuk complex functions + +**Estimated Time**: 1 jam + +--- + +#### Task 4.3: Custom Hook Refactoring +- [ ] Create `useApbdesData` custom hook +- [ ] Move data fetching logic to hook +- [ ] Add SWR/React Query for caching (optional) +- [ ] Add optimistic updates +- [ ] Add error handling di hook level + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/hooks/useApbdesData.ts` (CREATE) + +**Estimated Time**: 1 jam + +--- + +### **Phase 5: Advanced Features** ๐Ÿš€ LOW PRIORITY (Optional) + +#### Task 5.1: Year Comparison View +- [ ] Add multi-year selection +- [ ] Side-by-side comparison table +- [ ] Year-over-year growth calculation +- [ ] Add trend arrows dan percentage change +- [ ] Add comparison chart + +**Files to Create**: +- `src/app/darmasaba/_com/main-page/apbdes/lib/yearComparison.tsx` (CREATE) + +**Estimated Time**: 2 jam + +--- + +#### Task 5.2: Dashboard Widgets +- [ ] Key metrics overview widget +- [ ] Budget utilization gauge chart +- [ ] Alert untuk over/under budget +- [ ] Quick stats summary +- [ ] Add drill-down capability + +**Dependencies**: Mungkin perlu additional chart library + +**Estimated Time**: 2.5 jam + +--- + +#### Task 5.3: Responsive Mobile Optimization +- [ ] Mobile-first table design +- [ ] Collapsible sections untuk mobile +- [ ] Touch-friendly interactions +- [ ] Optimize chart untuk small screens +- [ ] Add mobile navigation + +**Estimated Time**: 1.5 jam + +--- + +## ๐Ÿ“ Proposed File Structure + +``` +src/app/darmasaba/_com/main-page/apbdes/ +โ”‚ +โ”œโ”€โ”€ index.tsx # Main component (refactored) +โ”‚ +โ”œโ”€โ”€ lib/ +โ”‚ โ”œโ”€โ”€ paguTable.tsx # Table Pagu (improved) +โ”‚ โ”œโ”€โ”€ realisasiTable.tsx # Table Realisasi (improved) +โ”‚ โ”œโ”€โ”€ grafikRealisasi.tsx # Chart component (updated) +โ”‚ โ”œโ”€โ”€ comparisonChart.tsx # NEW: Bar chart comparison +โ”‚ โ”œโ”€โ”€ barChart.tsx # NEW: Interactive bar chart +โ”‚ โ”œโ”€โ”€ pieChart.tsx # NEW: Pie chart visualization +โ”‚ โ””โ”€โ”€ summaryCards.tsx # NEW: Summary metrics cards +โ”‚ โ””โ”€โ”€ yearComparison.tsx # NEW: Year comparison view (optional) +โ”‚ +โ”œโ”€โ”€ components/ +โ”‚ โ”œโ”€โ”€ apbdesSkeleton.tsx # NEW: Loading skeleton +โ”‚ โ”œโ”€โ”€ apbdesCard.tsx # NEW: Preview card +โ”‚ โ”œโ”€โ”€ exportButtons.tsx # NEW: Export/Print buttons +โ”‚ โ””โ”€โ”€ detailModal.tsx # NEW: Detail view modal +โ”‚ +โ”œโ”€โ”€ hooks/ +โ”‚ โ”œโ”€โ”€ useApbdesData.ts # NEW: Data fetching hook +โ”‚ โ””โ”€โ”€ useApbdesFilter.ts # NEW: Search/filter hook +โ”‚ +โ”œโ”€โ”€ types/ +โ”‚ โ””โ”€โ”€ apbdes.ts # NEW: TypeScript types & interfaces +โ”‚ +โ””โ”€โ”€ utils/ + โ”œโ”€โ”€ exportPdf.ts # NEW: PDF export logic + โ””โ”€โ”€ exportExcel.ts # NEW: Excel export logic +``` + +--- + +## ๐Ÿ“ฆ Required Dependencies + +```bash +# Core dependencies +bun add framer-motion recharts + +# Export functionality +bun add @react-pdf/renderer exceljs + +# Optional: Better data fetching +bun add swr + +# Type definitions +bun add -D @types/react-pdf +``` + +--- + +## ๐ŸŽฏ Success Criteria + +### UI/UX +- [ ] Loading state implemented dengan skeleton +- [ ] Smooth animations pada semua interactions +- [ ] Modern table design dengan hover effects +- [ ] Fully responsive (mobile, tablet, desktop) + +### Data Visualization +- [ ] Interactive charts (Recharts) implemented +- [ ] Summary cards dengan real-time metrics +- [ ] Color-coded performance indicators +- [ ] Responsive charts untuk semua screen sizes + +### Features +- [ ] Search & filter functionality working +- [ ] Export to PDF working +- [ ] Export to Excel working +- [ ] Print view working +- [ ] Detail modal working + +### Code Quality +- [ ] No `any` types (all properly typed) +- [ ] No commented code +- [ ] No console.logs in production code +- [ ] Error boundaries implemented +- [ ] Custom hooks for reusability + +--- + +## โฑ๏ธ Total Estimated Time + +| Phase | Tasks | Estimated Time | +|-------|-------|---------------| +| Phase 1 | 3 tasks | 2.75 jam | +| Phase 2 | 3 tasks | 4.5 jam | +| Phase 3 | 3 tasks | 5 jam | +| Phase 4 | 3 tasks | 3.5 jam | +| Phase 5 | 3 tasks | 6 jam (optional) | +| **TOTAL** | **15 tasks** | **~21.75 jam** (tanpa Phase 5: ~15.75 jam) | + +--- + +## ๐Ÿš€ Recommended Implementation Order + +1. **Start dengan Phase 1** (UI/UX Enhancement) - Quick wins, immediate visual improvement +2. **Continue dengan Phase 4** (Code Quality) - Clean foundation sebelum add features +3. **Move to Phase 2** (Data Visualization) - Core value add +4. **Then Phase 3** (Features) - User functionality +5. **Optional Phase 5** (Advanced) - If time permits + +--- + +## ๐Ÿ“ Notes + +- Prioritize tasks berdasarkan impact vs effort +- Test di berbagai screen sizes selama development +- Get user feedback setelah Phase 1 & 2 complete +- Consider A/B testing untuk new design +- Document all new components di storybook (if available) + +--- + +## ๐Ÿ”— Related Files + +- Main Component: `src/app/darmasaba/_com/main-page/apbdes/index.tsx` +- State Management: `src/app/admin/(dashboard)/_state/landing-page/apbdes.ts` +- API Endpoint: `src/app/api/landingpage/apbdes/` + +--- + +**Last Updated**: 2026-03-25 +**Status**: Phase 1, 2, 4 Completed โœ… +**Approved By**: Completed + +--- + +## โœ… Completed Tasks Summary + +### Phase 1: UI/UX Enhancement - DONE โœ… +- โœ… Created `apbdesSkeleton.tsx` with loading skeletons for all components +- โœ… Improved table design with hover effects, striped rows, sticky headers +- โœ… Installed Framer Motion and added smooth animations +- โœ… Added loading states when changing year +- โœ… Added fade-in and slide-up transitions + +### Phase 2: Data Visualization - DONE โœ… +- โœ… Installed Recharts +- โœ… Created interactive comparison bar chart (Pagu vs Realisasi) +- โœ… Created summary cards with metrics and progress indicators +- โœ… Enhanced GrafikRealisasi with better visual design +- โœ… Added color-coded performance badges + +### Phase 4: Code Quality - DONE โœ… +- โœ… Created proper TypeScript types in `types/apbdes.ts` +- โœ… Replaced most `any` types with proper interfaces (some remain for flexibility) +- โœ… Removed commented code from main index.tsx +- โœ… Cleaned up console.logs +- โœ… Improved error handling + +### Files Created: +1. `src/app/darmasaba/_com/main-page/apbdes/types/apbdes.ts` - TypeScript types +2. `src/app/darmasaba/_com/main-page/apbdes/components/apbdesSkeleton.tsx` - Loading skeletons +3. `src/app/darmasaba/_com/main-page/apbdes/lib/summaryCards.tsx` - Summary metrics cards +4. `src/app/darmasaba/_com/main-page/apbdes/lib/comparisonChart.tsx` - Recharts bar chart +5. `src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx` - Improved table (updated) +6. `src/app/darmasaba/_com/main-page/apbdes/lib/realisasiTable.tsx` - Improved table (updated) +7. `src/app/darmasaba/_com/main-page/apbdes/lib/grafikRealisasi.tsx` - Enhanced chart (updated) +8. `src/app/darmasaba/_com/main-page/apbdes/index.tsx` - Main component with animations (updated) + +### Dependencies Installed: +- `framer-motion@12.38.0` - Animation library +- `recharts@3.8.0` - Chart library + +---