From 493344802a63ae57cfeaa80e58105725fcc5a1b5 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Wed, 21 May 2025 16:18:37 +0700 Subject: [PATCH 1/7] update upload disbursement file batch template --- .../file-templates/upload-batch-template.xlsx | Bin 9490 -> 9457 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/media/file-templates/upload-batch-template.xlsx b/public/media/file-templates/upload-batch-template.xlsx index 2af339b1dda6d09ba64378dc5731a67a4193cd74..e31ef5a5a27358d054581ffe6c74cf480d28c85b 100644 GIT binary patch delta 4537 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 delta 4602 zcmZ8lXEfa3+MN--MJE^rL$v6L-un=uMxsZF9-Tq*3&!XoMkk_6^pX&D^cp1?BBMo% z7KDU}dXxWK?tS0$VXw9K+UxA+d^v0F=Z9_zyfzC=G-ML?K?R)$76vQ>kc~ap1J_lY zqgSl;#~L4@QLu&_%wpxvwno>;ffC{{5AD%{4mbe!n;1G5}wu10G8G%TA-+_(1h-Q|TUIgu@%v2w$cFqXf(Y60I-FqW(iS z1caJqpOtp(HCrAy$V|vvQrY1ejpVo8@R#DxvXm79ico2CyK&b9sn6bK1^8ix&4^Y4 zZRgu!Jt4x&Xd;Tnm-UL&98jwCq#TkrO^} zGQ{XX?Djr$swpATI>6a&H($6z*Ic9mR__{3d7wQ=jN#EZPY`AP-^? zhy{f1g0TXLW;idL80AyWT0rcljV(QnY=yzI-s75FzC{qi+)FJGWRR&FB3Dl$AYlc02INjHgy%*_=Bf|6DLnvD;Q*rzse2p*0`cXObd5@ zods2-$7>^sO=Xu0(r?HKVuckAQ+TRs{SoT!D&&BOVC6DDb)E-dUo)3k3G?Z*U9(K= zV2DLr6Mk8QU#+>uXVhbcPRaPgvg6))@EF1WrjNvV|T1(+ZVH( z!aU5|c3Al?Kxl6hCuM=kcR6Xf}bR3{3iz)jiv|3b;bCumj9z*eR^#wb@nf!sJY!B0KoU$M% z95D%m?IhsEe7m-N?5@7a0>#ZTBBeC9o)O@+@cjYGl09Mg#v783!()1<=puslI*KYv zay|1Y`H)iH=Qkn-9oT}0C#-~^ZAkBf9aDWnVqd{?$C()v`BQ0|k3~?VcW-Lb6pg>X z9ukBib=Rh(3(70LTGfPHpHZ^g)QX?pIC=5BA&J!8Ft@n@mN!r%^vk2Pbh$-!MhNJ# zBtelFr&G-oL4+NG6$%rj?V{Y^GOuSZhvj?DlBruE4qXhmggWmy&jAamKBa`ZIR;!} z-S6j!d_YGn$ozG$hYq*YVWimI9)4YPU*~PvMFQ7B@w`VlNpkPK1`-@Q`QXc3wnl|j zrPJ!2{`r>T-VU9YbS<$S947sNAJs_nmIlk~&`z8!T_mSO@z*L!OeP7s@zr@8_S*d% z3{Mg|74ILAiQ{;}`URvS_q*34{IHyMUc!x%T8e``SG}j#(LW$u4GknvVzTx=yM!eW z2vmWdr(y?^6%BjDXi!10%gFUta@5B7~P9g>At9QUEg#^pJC z%_r@m4VMY3VJdvDYcoQyI$)XNPpcgnHKMqjP=Odok_ZfG!x6sr#m4pqHxo8~dL$O{ z%rp)~R#;?~4R&|R@b$NvYP&D>*qi4rh&|FRr_|Qu6C(AI4pH+M)|lbvKG7XaC+p!% z?JdF^)`Uf$Spyy|ohxsw40V`pw3sWAJ`HbT#(z)2q}3jgWMrJrLHx*76|nRgxJ@sC z%{`8vhPhM@`3+IBqlF&EZ?*cHGeQ+zNS)VTLTLh`HPVW)Ci&E81)kns|jbg*%&!nEB zl^%?LOwN^@On$_EYdSGJrf}oqT!)|Y>z$w+e$x*8mY~jxkv32fz@VJR*8sIikOKgO ze``-t{cv0GMwIUE3pvrt@}s?tSxk$KlW4)!!R}cWfmv^b(Kp$V^!w#4*-B?Gn?iDg zFIb*s-E>`ZI=F59row4Ew1JT;P7OQpu7ee!I&Xj5N^^=YO~d9C(Y|YdcG+_3f{{k< zM$KT23b(Llnz_Y`FhV2gx7O2?F93Nn?JlXi=0ggh6lQOS!Z`FVAY{KfvQKRZ9zk0D z{2(kRETISCrhS;8QS6axVK%@DqQ;A}r2 zv?sIXOF6!(nDoWamWe{Zie`VmL9L z7&9qd$Nakzxf<04qjITxENZQ4B?h13-ghxw(<}ms!EMSD$j*SfaNW-(@k4J`TUgKi ztkvGXE(@edQeT!SHiINM0Ey4^dm^``yOulzcZ?@dz*f?#!*$wWU;klm3iDn65l^q)SaETbqzV;_=w0cF4SY zbmFn1T+7cT)vAZ9J@nfro>Uq=7Bxmxr$(pY*7tix1M{tAJjAAbcYqUve9OK1o)z2D zneaN*P#U4lDnfgUK)t)@pSH`RqqqHEN-8H>;|tfuUx?~$w)alt+$<=o_YH-M8t-dL zyHHFe*rg%65_IakU0%P{k)SzDQpXz{az+GiJPF&pbK)wkt4ScuSe=rw`uR9E_=d>& zE7Yv#i$9n##o0QB2c+6SHzKEgurAFF^xJc6Gt6ouLx;462qgHii_{)Cj_r%D-Y%A< z&q6L0m!IUQw?28!@};hzr2<2?OVYkrTZTiGaLN;{of{TA*ZA2;^ISgmkz4_oq^FX` ze-t$X&i_`fC(UoH>pFP$8ax}S2j)yV~~GnR3I0aBa6h2#i|EUl5$6fLdPG_6rsMN)$!)kq^RM-X4P)5E=zIjo;(tj1Kk)ZKsu z`V?QKY6>AA|85TBIlz6zm{mZnZGZLwzs*gpJTESU;e}Wj)b)7(NFve_7WHJq#h&dB zd-5;CdS3$$`$7r8aVz_2b2AEy)nxxIURi$X%A`M3xXaLS>cJHtxl}$=xPv|0Hfvj# z2=fV7ULWfSCq2hOJj3xPI5q0aZIf)rOQ|9@{=wlN((!O+03)hq>hkqOz5=3E(kdp> z{f24biw|vKp&jpW8i~-+)j)vM50i|&%dd4Sd2%0;dwV}-@QTA@pbCaDcA?qjf*!)f z4LmSmN0SsM(UDTvoK1SK*gC?Vu4ng^=_8O2#4Bpv+iJeM*JOkjDNFwrN#k>?&OQy9 z%)zP`9I?j;44W69r3@%#zWin~NOqf!lQ~uneh4LDChxusQ!ALUrrEAcSEG_)iMAx4 z9Q`e9h9yu#y`>#iw6Bh2T&6n)-SLtpU2cqt`66?`$6TkBF%JQ}QT5SD*|!h8^rAFw zvEiFa)Cx;!PQLp!U8-dm#@7Vu!Nx2c1x-mF`6#U4*^kqTb#n!a}#H~xVSe|gDYP+VMW zB+;Au1EK7BqR@&+YfC}i!w-Ljf7Gv&3Zb~76-Gp((u?$sU-zp%3IRF4-7_}9mQ+mW z_)|t-)5WXQ(<3`|YFp`tkIPsilUyVtJ}?%%i%~NOOp@aq3UMNxC0=_dfDWMPE>$Y! z@mTuI=bgfT7}JL75Z-87H`eMvhz)!{jlrD0h#tXaENMBc0mcbZHFV&XNm0 zH!|SuR?m>X^^M5MPmmVcGVMtu%AaEri?_S!*?93w$);Mb2Q6Ugh+z4mqi|dnfYQ~_ zXEA=i_w@4&oki&MD;^#ue^jp4M+6M}ld60#%t5*qh9e?KIn znyD==hVbu62B!7iA+JN_8Y80xqDW?vO}gn13k3SerfLCwP=1OEPapXoF)l{DB&Lhi z7fvf(${=l_ZXmGIpR$5-C7rAbvx|!fw+uPP|8<3be@F+fY)K4@UL4CmRtH_5$lGhF`9kUDacrer!Sb^-Z^RQB z0P(*$+@&`)DgRFJVe7wa++HCJ(rwqNUro-T_7kGgvpYVA`T}PkLYpO<=FM#VE}M+( zx46O>k?kztt%bYja{@kAe|c%?^&nCE_eppA`p>$*CRah0NT>zc8w`Cnh9$=o zMNdpUYMsVAzSadt1j3%AR#4o6KHE{Xa31H2;f-<+pBv8XW%6i$4veyy*DD^~{*HBx zcq)1T7k3=O_%xVU>fJI01W;adO*M6Nv8;ZU5 zeTAO1ybXG`mz_F7q89@A6vubvM$yU*lUfg08$RBQa4)w>k=x43I-i%MR9z;D?2XT>c@@o#_Lr0nWYudjND95LYgSrME>BN$ zkxJ{-@LC^6$i7(`fErR$zVJJIFKj@PZq_F$F%YFURp4&6g-EWJxJfokt3SU!Ibr0> zsJi(*wQRM#{4f<9bCg`tH7SaiFtWNuMei1$5KtuxY4qI#X5DD`Q>o9=^o9HeSTDjC zIOTf0mIC%$(;bdmo05uxzW=D&TioffA8)Sm+pR9LYhipSEmBR2gcxqUPpYbSG`aH1 zGOh`bbULoh+a0#p`JSeHcO@&;3o}3lpP_%GnHl{}r$DKup38y1thj;R45|0zYil^? zm{KskvQ^qHuqicYQ-}%q$||xV!i^ehd6OGQ$uS~K{F^#mNvU#~`x@SK#ucRN7$#l2 zKT!P%;uh3X?R45+z0lekox3u>u+-Y<>@qeEGVpCU!D=0r zly96;__0CuGaSPfFp+V6?Geeg6k{)OB02B08R7^}FnWc4Ny65EVOJ&uTcfX_D&T&! z3YR2!8|}}9{_l+mCATT~6m8F~LSjbvPeVXIfU%=Hd8i5KIMCDFx52V#a-Li4|J$Cx zAP~c!D)IM#LC`-qNQM6T=ZAOYp}G10`^LXbqcs1~KG3vW(7y@bH1s&n9dH|(7^VWA hLu Date: Wed, 21 May 2025 16:18:50 +0700 Subject: [PATCH 2/7] set desc true on disbursement table list --- .../disbursement/history-transaction/HistoryTransaction.tsx | 2 +- .../history-transaction/hooks/TransactionContext.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/disbursement/history-transaction/HistoryTransaction.tsx b/src/pages/disbursement/history-transaction/HistoryTransaction.tsx index 61b9d2d..792a69f 100644 --- a/src/pages/disbursement/history-transaction/HistoryTransaction.tsx +++ b/src/pages/disbursement/history-transaction/HistoryTransaction.tsx @@ -23,7 +23,7 @@ const HistoryTransactionDisbursement = () => { - History Disbursement + Disbursement
diff --git a/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx b/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx index 50829d6..861dcea 100644 --- a/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx +++ b/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx @@ -285,7 +285,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { pagination={{ size: 10 }} toolbar={} layout={{ card: true }} - sorting={[{ id: 'execution_date', desc: false }]} + sorting={[{ id: 'execution_date', desc: true }]} serverSide={true} onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => getTransactionLists(pageIndex, pageSize, sorting, columnFilters) From a0fe50164f3e5650f7e60b6e0490ce7f0a567be2 Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Wed, 21 May 2025 16:42:37 +0700 Subject: [PATCH 3/7] update --- .../dashboards/home/DashboardHomePage.tsx | 2 +- .../home/blocks/ShowDetailWalletDialog.tsx | 490 ++++++++---------- 2 files changed, 222 insertions(+), 270 deletions(-) diff --git a/src/pages/dashboards/home/DashboardHomePage.tsx b/src/pages/dashboards/home/DashboardHomePage.tsx index 71ba39a..369149c 100644 --- a/src/pages/dashboards/home/DashboardHomePage.tsx +++ b/src/pages/dashboards/home/DashboardHomePage.tsx @@ -269,7 +269,7 @@ const DashboardHomePage = () => {
{bankaccount?.data && bankaccount?.data.length > 0 - && getAuth()?.statusbalance=='Y' + // && getAuth()?.statusbalance=='Y' ? ( bankaccount?.data.map((bankaccountdatas: { id_balance:string,amount: string, credit_limit: string, monthly_limit: string; wallet: string; }, index: number) => ( void; @@ -58,107 +41,23 @@ const getDefaultDateRange = () => { }; }; -const columns = [ - { - accessorKey: 'transaction_code', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[120px]' }, - }, - { - accessorKey: 'msisdn_reff', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[120px]' }, - }, - { - accessorKey: 'transaction_type.name', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[180px]' }, - }, - { - accessorKey: 'type', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[80px]' }, - }, - { - accessorKey: 'amount', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue()?.toFixed(2), - meta: { headerClassName: 'min-w-[100px]' }, - }, - { - accessorKey: 'pre_amount', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue()?.toFixed(2), - meta: { headerClassName: 'min-w-[100px]' }, - }, - { - accessorKey: 'post_amount', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue()?.toFixed(2), - meta: { headerClassName: 'min-w-[100px]' }, - }, - { - accessorKey: 'category', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[80px]' }, - }, - { - accessorKey: 'date', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => { - const val = info.getValue(); - if (!val) return '-'; - return new Date(val).toLocaleString('id-ID', { - day: '2-digit', - month: 'short', - year: 'numeric', - hour: '2-digit', - minute: '2-digit', - }); - }, - meta: { headerClassName: 'min-w-[150px]' }, - }, - { - accessorKey: 'purpose', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue() || '-', - meta: { headerClassName: 'min-w-[200px]' }, - }, - { - accessorKey: 'notes', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue() || '-', - meta: { headerClassName: 'min-w-[200px]' }, - }, -]; - const ShowDetailWalletDialog: React.FC = ({ open, onClose, idbalance, }) => { const { GetData } = useCallApi(); - const [data, setData] = useState([]); - const [isLoading, setIsLoading] = useState(false); + const [dateRange, setDateRange] = useState(getDefaultDateRange()); const [selectedTransferType, setSelectedTransferType] = useState(null); + const [transferType, setTransferType] = useState([]); const [selectedCategory, setSelectedCategory] = useState(null); const [searchValue, setSearchValue] = useState(''); - const [transferType, setTransferType] = useState([]); const [category, setCategory] = useState([]); + const [transaction, setTransaction] = useState([]); + const [filters, setFilters] = useState({}); - const fetchTransferType = async () => { + const fetchTransferType = useCallback(async () => { try { const response = await GetData(`${apiConfig.service_transaction}/transactiontype/list`, { limit: 100, @@ -171,71 +70,18 @@ const ShowDetailWalletDialog: React.FC = ({ } catch (error) { console.error('Error fetching transfer types', error); } - }; + }, [GetData]); - const getDetailList = useCallback( - async ( - limit: number, - page: number, - with_deleted: boolean, - order_field: string, - order_direction: string, - filter: any - ): Promise => { - if (!idbalance) return []; - try { - const response = await GetData( - `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${idbalance}`, - { - limit, - page, - with_deleted, - order_field, - order_direction, - filter: JSON.stringify(filter), - } - ); - return response?.data?.list || []; - } catch (error) { - console.error('Error fetching wallet detail:', error); - return []; - } - }, - [GetData, idbalance] - ); + useEffect(() => { + fetchTransferType(); + }, [fetchTransferType]); - const fetchData = useCallback( - async (params: { - pageIndex: number; - pageSize: number; - sorting: Array<{ id: string; desc: boolean }>; - columnFilters: any[]; - }): Promise<{ data: WalletTransaction[] }> => { - // setIsLoading(true); - const order_field = params.sorting.length ? params.sorting[0].id : 'date'; - const order_direction = params.sorting.length && params.sorting[0].desc ? 'DESC' : 'ASC'; - const result = await getDetailList( - params.pageSize, - params.pageIndex + 1, - false, - order_field, - order_direction, - params.columnFilters - ); - setData(result); - setIsLoading(false); - return { data: result }; - }, - [getDetailList] - ); - - // Ambil unique category dari data transaksi setelah data di-fetch useEffect(() => { const uniqueCategories = Array.from( - new Set(data.map((tx) => tx.category).filter((cat) => !!cat)) + new Set(transaction.map((tx) => tx.category).filter((cat) => !!cat)) ); setCategory(uniqueCategories); - }, [data]); + }, [transaction]); const handleTransferTypeChange = (value: string) => { setSelectedTransferType(value === 'all' ? null : value); @@ -250,30 +96,136 @@ const ShowDetailWalletDialog: React.FC = ({ setSelectedTransferType(null); setSelectedCategory(null); setSearchValue(''); + setFilters({}); }; - useEffect(() => { - fetchTransferType(); - }, []); + const handleApplyFilters = () => { + const appliedFilters: any = {}; - useEffect(() => { - if (!open) return; + if (dateRange.from) appliedFilters.date_from = dateRange.from+" 00:00:00"; + if (dateRange.to) appliedFilters.date_to = dateRange.to+" 23:59:59"; + if (selectedTransferType) appliedFilters.transaction_type_id = selectedTransferType; + if (selectedCategory) appliedFilters.category = selectedCategory; + if (searchValue) appliedFilters.transaction_code = searchValue; - const filters = []; + setFilters(appliedFilters); + }; - if (dateRange.from) filters.push({ id: 'date', value: { gte: dateRange.from } }); - if (dateRange.to) filters.push({ id: 'date', value: { lte: dateRange.to } }); - if (selectedTransferType) filters.push({ id: 'transaction_type.id', value: selectedTransferType }); - if (selectedCategory) filters.push({ id: 'category', value: selectedCategory }); - if (searchValue) filters.push({ id: 'transaction_code', value: searchValue }); - fetchData({ - pageIndex: 0, - pageSize: 10, - sorting: [{ id: 'date', desc: true }], - columnFilters: filters, - }); - }, [dateRange, selectedTransferType, selectedCategory, searchValue, open]); + const columns = [ + { + accessorKey: 'transaction_code', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[120px]' }, + }, + { + accessorKey: 'msisdn_reff', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[120px]' }, + }, + { + accessorKey: 'transaction_type.name', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[180px]' }, + }, + { + accessorKey: 'type', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[80px]' }, + }, + { + accessorKey: 'amount', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue()?.toFixed(2), + meta: { headerClassName: 'min-w-[100px]' }, + }, + { + accessorKey: 'pre_amount', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue()?.toFixed(2), + meta: { headerClassName: 'min-w-[100px]' }, + }, + { + accessorKey: 'post_amount', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue()?.toFixed(2), + meta: { headerClassName: 'min-w-[100px]' }, + }, + { + accessorKey: 'category', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[80px]' }, + }, + { + accessorKey: 'date', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => { + const val = info.getValue(); + if (!val) return '-'; + return new Date(val).toLocaleString('id-ID', { + day: '2-digit', + month: 'short', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }); + }, + meta: { headerClassName: 'min-w-[150px]' }, + }, + { + accessorKey: 'purpose', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue() || '-', + meta: { headerClassName: 'min-w-[200px]' }, + }, + { + accessorKey: 'notes', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue() || '-', + meta: { headerClassName: 'min-w-[200px]' }, + }, + ]; + + const getTransactionLists = useCallback( + async (page: number, limit: number, sorting: any, _columnFilters: any) => { + // console.log(idbalance); + try { + const response = await GetData(`${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${idbalance}`, { + limit, + page: page + 1, + with_deleted: false, + order_field: "created_at", + order_direction: 'DESC', + filter: filters + }); + + // console.log(filters); + + if (!response || !response.data) { + console.warn('No data received:', response); + return { data: [], totalCount: 0 }; + } + + setTransaction(response.data.list); + return { data: response.data.list, totalCount: response.data.total_count }; + } catch (error) { + console.error('Error fetching transaction', error); + return { data: [], totalCount: 0 }; + } + }, + [GetData, idbalance, filters] + ); return ( @@ -281,98 +233,98 @@ const ShowDetailWalletDialog: React.FC = ({ Details Wallet Statement + + -
- {/*
-
- +
+
+ - + -
- -
- -
- -
- - - - - - +
+
-
*/} +
+ +
+ + + + + + + + +
+
+ +
{ - return await fetchData({ - pageIndex: params.pageIndex, - pageSize: params.pageSize, - sorting: params.sorting ?? [], - columnFilters: params.columnFilters ?? [], - }); - }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getTransactionLists(pageIndex, pageSize, sorting, columnFilters) + } />
@@ -381,4 +333,4 @@ const ShowDetailWalletDialog: React.FC = ({ ); }; -export default ShowDetailWalletDialog; \ No newline at end of file +export default ShowDetailWalletDialog; From 831627c371626498542aad546aa0d3cfbcf0c2b0 Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Wed, 21 May 2025 16:59:04 +0700 Subject: [PATCH 4/7] update button filter --- .../dashboards/home/DashboardHomePage.tsx | 2 +- .../blocks/ListToolbar.tsx | 134 ++++++++---------- .../blocks/ListToolbar.tsx | 133 +++++++---------- 3 files changed, 109 insertions(+), 160 deletions(-) diff --git a/src/pages/dashboards/home/DashboardHomePage.tsx b/src/pages/dashboards/home/DashboardHomePage.tsx index 369149c..71ba39a 100644 --- a/src/pages/dashboards/home/DashboardHomePage.tsx +++ b/src/pages/dashboards/home/DashboardHomePage.tsx @@ -269,7 +269,7 @@ const DashboardHomePage = () => {
{bankaccount?.data && bankaccount?.data.length > 0 - // && getAuth()?.statusbalance=='Y' + && getAuth()?.statusbalance=='Y' ? ( bankaccount?.data.map((bankaccountdatas: { id_balance:string,amount: string, credit_limit: string, monthly_limit: string; wallet: string; }, index: number) => ( { const { table, reload } = useDataGrid(); - // Set the initial state for trxDate + // State untuk filter const [trxDate, settrxDate] = useState({ from: '', to: '' }); - const [statusApproval, setStatusApproval] = useState( - (table.getColumn('status_approve')?.getFilterValue() as string) ?? '' - ); + const [statusApproval, setStatusApproval] = useState(''); + const [searchValue, setSearchValue] = useState(''); + const [typeSearchValue, setSearchTypeValue] = useState(''); - useEffect(() => { - const timer = setTimeout(() => { - table.getColumn('status_approve')?.setFilterValue(statusApproval); - table.setPageIndex(0); - }, 200); - return () => clearTimeout(timer); - }, [statusApproval, table]); - - // Function to format date to YYYY-MM-DD - const formatDate = (date: Date): string => { - return date.toISOString().split('T')[0]; - }; - - const [searchValue, setSearchValue] = useState(); - const [typeSearchValue, setSearchTypeValue] = useState(); - - - - // useEffect to set the default date values + // Set tanggal default saat pertama mount useEffect(() => { const today = new Date(); - // const firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); + const formatDate = (date: Date) => date.toISOString().split('T')[0]; settrxDate({ from: formatDate(today), to: formatDate(today), }); }, []); + // Fungsi untuk apply semua filter sekaligus saat tombol Filter ditekan const handleFilterData = useCallback(() => { try { + if (!trxDate.from || !trxDate.to) { + toast.error('Please select From and To dates'); + return; + } + + // Set filter tanggal table.getColumn('transaction_date')?.setFilterValue(trxDate); + + // Set filter status approval + table.getColumn('status_approve')?.setFilterValue(statusApproval || ''); + + // Set filter search type sebagai column filter id 'searchtype' + table.setColumnFilters((prevFilters) => { + // Hapus dulu filter dengan id 'searchtype' dan 'code' agar gak duplikat + const filtered = prevFilters.filter( + (f) => f.id !== 'searchtype' && f.id !== 'code' + ); + + // Tambahkan filter baru jika ada + if (typeSearchValue) { + filtered.push({ id: 'searchtype', value: typeSearchValue }); + } + if (searchValue) { + filtered.push({ id: 'code', value: searchValue }); + } + + return filtered; + }); + + // Reset ke halaman pertama + table.setPageIndex(0); } catch (error) { toast.error('Error applying filter'); - console.error('Error applying filter:', error); + console.error(error); } - }, [trxDate, table]); - - useEffect(() => { - const timer = setTimeout(() => { - // Add search type filter to column filters - table.setColumnFilters((prev) => [ - ...prev.filter((f) => f.id !== 'searchtype'), - { id: 'searchtype', value: typeSearchValue }, - ]); - table.setPageIndex(0); - }, 200); - return () => clearTimeout(timer); - }, [typeSearchValue, table]); - - - useEffect(() => { - const timer = setTimeout(() => { - table.getColumn('code')?.setFilterValue(searchValue); - table.setPageIndex(0); - }, 200); - - return () => clearTimeout(timer); - }, [searchValue, table]); - - useEffect(() => { - if (trxDate.from && trxDate.to) { - handleFilterData(); - } - }, [trxDate]); + }, [trxDate, statusApproval, searchValue, typeSearchValue, table]); return (
@@ -93,11 +78,8 @@ const ListToolbar = () => { From - settrxDate({ ...trxDate, from: event.target.value }) - } + onChange={(e) => settrxDate({ ...trxDate, from: e.target.value })} name="from" /> @@ -106,20 +88,15 @@ const ListToolbar = () => { To - settrxDate({ ...trxDate, to: event.target.value }) - } + onChange={(e) => settrxDate({ ...trxDate, to: e.target.value })} name="to" /> { - setSearchTypeValue(value); - }} + onValueChange={setSearchTypeValue} > @@ -151,12 +126,16 @@ const ListToolbar = () => { setSearchValue(event.target.value)} + onChange={(e) => setSearchValue(e.target.value)} /> + {/* Tombol Filter */} +
@@ -166,23 +145,22 @@ const ListToolbar = () => { className="h-7.5" onClick={() => { const today = new Date(); - // const firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); + const formatDate = (date: Date) => date.toISOString().split('T')[0]; - // Resetting all filters + // Reset semua filter dan tanggal ke hari ini setSearchValue(''); setStatusApproval(''); - settrxDate({ - from: formatDate(today), - to: formatDate(today), - }); - + settrxDate({ from: formatDate(today), to: formatDate(today) }); setSearchTypeValue(''); + // Reset filter di tabel table.getColumn('code')?.setFilterValue(''); table.getColumn('status_approve')?.setFilterValue(''); + table.getColumn('transaction_date')?.setFilterValue(''); + table.setColumnFilters([]); table.setPageIndex(0); - reload(); // Reload table data + reload(); }} > diff --git a/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx index 2a56ce4..72987dc 100644 --- a/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx +++ b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx @@ -1,7 +1,7 @@ import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; import { useTransactionContext } from '../hooks/useTransactionContext'; import { Button } from '@/components/ui/button'; -import { useCallback, useState, useEffect } from 'react'; +import { useCallback, useState, useEffect, useRef } from 'react'; import { toast } from 'sonner'; import { Select, @@ -17,8 +17,8 @@ import { getAuth } from '@/auth'; const ListToolbar = () => { const { table, reload } = useDataGrid(); const [trxDate, settrxDate] = useState({ from: '', to: '' }); - const [searchValue, setSearchValue] = useState(''); // default: empty string - const [typeSearchValue, setSearchTypeValue] = useState(''); // default: empty string + const [searchValue, setSearchValue] = useState(''); + const [typeSearchValue, setSearchTypeValue] = useState(''); const [typeValue, setTypeValue] = useState( (table.getState().columnFilters.find(f => f.id === 'kind')?.value as string) ?? '' ); @@ -26,62 +26,44 @@ const ListToolbar = () => { const { GetData } = useCallApi(); const API_URL = apiConfig.transaction; - const formatDate = (date: Date): string => { - return date.toISOString().split('T')[0]; - }; + const formatDate = (date: Date): string => date.toISOString().split('T')[0]; + // Set tanggal default hari ini saat mount useEffect(() => { const today = new Date(); - settrxDate({ - from: formatDate(today), - to: formatDate(today), - }); + const formatted = formatDate(today); + settrxDate({ from: formatted, to: formatted }); }, []); - useEffect(() => { - const timer = setTimeout(() => { - table.setColumnFilters((prev) => [ - ...prev.filter((f) => f.id !== 'kind'), - { id: 'kind', value: typeValue }, - ]); - table.setPageIndex(0); - }, 200); - return () => clearTimeout(timer); - }, [typeValue, table]); - - useEffect(() => { - const timer = setTimeout(() => { - table.setColumnFilters((prev) => [ - ...prev.filter((f) => f.id !== 'searchtype'), - { id: 'searchtype', value: typeSearchValue }, - ]); - table.setPageIndex(0); - }, 200); - return () => clearTimeout(timer); - }, [typeSearchValue, table]); - - useEffect(() => { - const timer = setTimeout(() => { - table.getColumn('code')?.setFilterValue(searchValue); - table.setPageIndex(0); - }, 200); - return () => clearTimeout(timer); - }, [searchValue, table]); + // **Hilangkan semua useEffect yang auto apply filter saat input berubah** + // Karena kamu mau filter apply hanya lewat tombol Filter + // Fungsi untuk apply SEMUA filter sekaligus saat tombol Filter diklik const handleFilterData = useCallback(() => { - try { - table.getColumn('transaction_date')?.setFilterValue(trxDate); - } catch (error) { - toast.error('Error applying filter'); - console.error('Error applying filter:', error); + if (!trxDate.from || !trxDate.to) { + toast.error('Please select both From and To dates'); + return; } - }, [trxDate, table]); - useEffect(() => { - if (trxDate.from && trxDate.to) { - handleFilterData(); - } - }, [trxDate]); + // Terapkan filter tanggal + table.getColumn('transaction_date')?.setFilterValue(trxDate); + + // Terapkan filter jenis transaksi (kind) + table.setColumnFilters((prev) => { + // Hapus filter 'kind' dan 'searchtype' agar bisa set ulang + const others = prev.filter(f => f.id !== 'kind' && f.id !== 'searchtype' && f.id !== 'code'); + // Bangun array baru dengan filter yang diinginkan + const filters: any[] = [...others]; + + if (typeValue) filters.push({ id: 'kind', value: typeValue }); + if (typeSearchValue) filters.push({ id: 'searchtype', value: typeSearchValue }); + if (searchValue) filters.push({ id: 'code', value: searchValue }); + + return filters; + }); + + table.setPageIndex(0); + }, [trxDate, typeValue, typeSearchValue, searchValue, table]); const exporDataToExcel = async ( typeSearchValue: string, @@ -93,8 +75,8 @@ const ListToolbar = () => { const formattedFilter: any = { "Transactions.transaction_date": { from: `${trxDate.from} 00:00:00`, - to: `${trxDate.to} 23:59:59` - } + to: `${trxDate.to} 23:59:59`, + }, }; if (typeSearchValue === 'msisdn') { @@ -106,17 +88,20 @@ const ListToolbar = () => { } if (typeValue) { - formattedFilter["Transactions.kind"] = typeValue; + formattedFilter['Transactions.kind'] = typeValue; } const filterParam = encodeURIComponent(JSON.stringify(formattedFilter)); - const response = await fetch(`${API_URL}/transaction/export?filter=${filterParam}`, { - method: 'GET', - headers: { - Authorization: `Bearer ${getAuth()?.access_token}`, // ganti dengan token kamu + const response = await fetch( + `${API_URL}/transaction/export?filter=${filterParam}`, + { + method: 'GET', + headers: { + Authorization: `Bearer ${getAuth()?.access_token}`, + }, } - }); + ); if (!response.ok) { throw new Error('Failed to fetch file'); @@ -161,16 +146,11 @@ const ListToolbar = () => { name="to" /> - - setTypeValue(value)}> - TRANSFER PURCHASE WITHDRAW @@ -193,10 +173,7 @@ const ListToolbar = () => { - setSearchTypeValue(value)}> @@ -216,6 +193,11 @@ const ListToolbar = () => { onChange={(event) => setSearchValue(event.target.value)} /> + + +
@@ -245,28 +227,17 @@ const ListToolbar = () => { Export Data - - - -
-
- -
- {isLoading ? ( -
Loading details...
- ) : filteredTransactions.length > 0 ? ( -
-
- - - - - - - - - - - - - - - - {filteredTransactions.map((transaction) => ( - - - - - - - - - - - - ))} - -
Transaction CodeTransaction TypeTypeAmountPre AmountPost AmountCategoryDateNotes
{transaction.transaction_code} - {transaction.transaction_type?.name || 'N/A'} - {transaction.type}{transaction.amount.toFixed(2)}{transaction.pre_amount.toFixed(2)}{transaction.post_amount.toFixed(2)}{transaction.category} - {new Date(transaction.date).toLocaleString('id-ID', { - day: '2-digit', - month: 'short', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - })} - {transaction.notes || '-'}
-
-
- ) : ( -
No transaction data available
- )} -
- - -
- ); -}; - -export default ShowDialog; diff --git a/src/pages/wallet/wallet-history/hooks/useManageWalletHistoryContext.tsx b/src/pages/wallet/wallet-history/hooks/useManageWalletHistoryContext.tsx deleted file mode 100644 index 9e5f912..0000000 --- a/src/pages/wallet/wallet-history/hooks/useManageWalletHistoryContext.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useContext } from 'react'; -import { ManageWalletContext } from './ManageWalletHistoryContext'; - -const useManageWalletContext = () => { - const context = useContext(ManageWalletContext); - if (!context) { - throw new Error('useManageWalletContext must be used within a ManageWalletContextProvider'); - } - return context; -}; - -export { useManageWalletContext }; diff --git a/src/pages/wallet/wallet-history/WalletHistory.tsx b/src/pages/wallet/wallet-statement/WalletStatement.tsx similarity index 93% rename from src/pages/wallet/wallet-history/WalletHistory.tsx rename to src/pages/wallet/wallet-statement/WalletStatement.tsx index 641ba29..ab6a685 100644 --- a/src/pages/wallet/wallet-history/WalletHistory.tsx +++ b/src/pages/wallet/wallet-statement/WalletStatement.tsx @@ -1,9 +1,9 @@ import { Container, DataGridInner } from '@/components'; -import { ManageWalletContextProvider } from './hooks/ManageWalletHistoryContext'; import { Breadcrumbs, Link } from '@mui/material'; import { Helmet } from 'react-helmet'; +import { ManageWalletContextProvider } from './hooks/ManageWalletStatementContext'; -const WalletHistory = () => { +const WalletStatement = () => { return ( <> @@ -35,4 +35,4 @@ const WalletHistory = () => { ); }; -export default WalletHistory; +export default WalletStatement; diff --git a/src/pages/wallet/wallet-history/blocks/ListToolbar.tsx b/src/pages/wallet/wallet-statement/blocks/ListToolbar.tsx similarity index 100% rename from src/pages/wallet/wallet-history/blocks/ListToolbar.tsx rename to src/pages/wallet/wallet-statement/blocks/ListToolbar.tsx diff --git a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx new file mode 100644 index 0000000..33d7ede --- /dev/null +++ b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx @@ -0,0 +1,503 @@ +import { useEffect, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { useManageStatementContext } from '../hooks/useManageWalletStatementContext'; +import { DefaultTooltip, KeenIcon } from '@/components'; +import { toast } from 'sonner'; +import { Button } from '@/components/ui/button'; +import { useCallApi } from '@/hooks'; +import { apiConfig } from '@/config/api.config'; + +const API_URL_WALLET = apiConfig.service_wallet; +const API_URL = apiConfig.service_transaction; + +interface TransactionType { + id: string; + name: string; +} + +interface WalletTransaction { + ID: string; + id_balance: string; + transaction_code: string; + transaction_type: { + id: string; + name: string; + }; + type: string; + amount: number; + pre_amount: number; + post_amount: number; + category: string; + notes: string; + date: string; + msisdn_reff: string; + purpose: string; +} + +const ShowDialog = () => { + const { showDetailDialog, setShowDetailDialog, selectedWallet } = useManageStatementContext(); + const [isLoading, setIsLoading] = useState(false); + const { GetData } = useCallApi(); + + const [transactionType, setTransactionType] = useState([]); + const [filteredTransactions, setFilteredTransactions] = useState([]); + + const [currentPage, setCurrentPage] = useState(1); + const [totalItems, setTotalItems] = useState(0); + const [totalPages, setTotalPages] = useState(1); + const itemsPerPage = 10; + + const getDefaultDateRange = () => { + const today = new Date(); + today.setHours(23, 59, 59, 999); + + const sevenDaysAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); + sevenDaysAgo.setHours(0, 0, 0, 0); + + return { + from: formatDate(sevenDaysAgo, true), + to: formatDate(today, true) + }; + }; + + const formatDate = (date: Date, includeTime = false) => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + + if (includeTime) { + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`; + } + + return `${year}-${month}-${day}`; + }; + + const [dateRange, setDateRange] = useState(getDefaultDateRange()); + const [category, setCategory] = useState(null); + const [selectedCategory, setSelectedCategory] = useState(''); + const [selectedTransactionType, setSelectedTransactionType] = useState(''); + const [searchValue, setSearchValue] = useState(''); + + const TransactionKind = { + return: 'R', + transfer: 'T', + purchase: 'P', + purchase_loja: 'L', + withdraw: 'W', + topup: 'U', + topup_p24: 'B', + topup_partner: 'N', + reward: 'E', + transfer_agent: 'A', + withdraw_agent: 'M', + topup_agent: 'O', + transfer_p24: 'S', + withdraw_merchant: 'I', + donation: 'D', + fee: 'F', + raversal: 'V', + cashback_cash: 'C', + cashback_point: 'H', + withdraw_admin: 'J' + }; + + type TransactionKindValue = (typeof TransactionKind)[keyof typeof TransactionKind]; + + const fetchTransactionType = async () => { + try { + setIsLoading(true); + const response = await GetData(`${API_URL}/transactiontype/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: 'created_at', + order_direction: 'ASC' + }); + setTransactionType( + (response?.data?.list || []).sort((a: any, b: any) => a.name.localeCompare(b.name)) + ); + } catch (error) { + console.error('Error fetching Transaction type', error); + toast.error('Failed to load transaction types'); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + fetchTransactionType(); + }, []); + + const fetchFilteredTransactions = async () => { + if (!selectedWallet?.ID) return; + + setIsLoading(true); + try { + let fromDateTime = dateRange.from; + if (!fromDateTime.includes('T')) { + const fromDate = new Date(fromDateTime); + fromDateTime = formatDate(fromDate, true); + } + + let toDateTime = dateRange.to; + if (!toDateTime.includes('T')) { + const toDate = new Date(toDateTime); + toDate.setHours(23, 59, 59, 999); + toDateTime = formatDate(toDate, true); + } + + const response = await GetData( + `${API_URL_WALLET}/dashboard/balance/list-balance-detail/${selectedWallet.ID}`, + { + limit: itemsPerPage, + page: currentPage, + order_field: 'created_at', + order_direction: 'DESC', + start_date: fromDateTime, + end_date: toDateTime, + transaction_type: selectedTransactionType || undefined, + category: selectedCategory || undefined, + search: searchValue || undefined + } + ); + console.log(response); + setFilteredTransactions(response?.data?.list || []); + setTotalItems(response?.data?.total || 0); + setTotalPages(Math.ceil((response?.data?.total || 0) / itemsPerPage)); + } catch (error) { + console.error('Error fetching filtered transactions:', error); + toast.error('Failed to load filtered transactions'); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + if (!showDetailDialog || !selectedWallet?.ID) return; + + const timer = setTimeout(() => { + fetchFilteredTransactions(); + }, 300); + + return () => clearTimeout(timer); + }, [ + showDetailDialog, + dateRange.from, + dateRange.to, + selectedTransactionType, + selectedCategory, + searchValue, + selectedWallet?.ID, + currentPage + ]); + + const handleSearchChange = (e: React.ChangeEvent) => { + const value = e.target.value; + setSearchValue(value); + }; + + const handleDateChange = (type: 'from' | 'to', value: string) => { + const date = new Date(value); + + if (type === 'from') { + date.setHours(0, 0, 0, 0); + } else { + date.setHours(23, 59, 59, 999); + } + + const formattedDate = formatDate(date, true); + console.log(`Setting ${type} date to:`, formattedDate); + setDateRange((prev) => ({ ...prev, [type]: formattedDate })); + }; + + const handleClearAllFilters = () => { + const defaultDates = getDefaultDateRange(); + console.log('Resetting filters to default:', defaultDates); + setDateRange(defaultDates); + setSelectedTransactionType(''); + setSearchValue(''); + setSelectedCategory(''); + setCurrentPage(1); + }; + + const handlePageChange = (page: number) => { + setCurrentPage(page); + }; + + useEffect(() => { + if (!showDetailDialog) return; + + const checkNewDay = () => { + const now = new Date(); + const currentDate = formatDate(now); + const fromDate = new Date(dateRange.from); + + if ( + currentDate !== formatDate(new Date(dateRange.to)) && + now.getTime() - fromDate.getTime() > 7 * 24 * 60 * 60 * 1000 + ) { + setDateRange(getDefaultDateRange()); + toast.info('Date range has been updated to the current period'); + } + }; + + checkNewDay(); + + const interval = setInterval(checkNewDay, 60 * 60 * 1000); + return () => clearInterval(interval); + }, [showDetailDialog, dateRange]); + + const getDisplayDate = (dateTimeString: string) => { + if (!dateTimeString) return ''; + return dateTimeString.split('T')[0]; + }; + + return ( + + + + Details Wallet Statement + + +
+
+ + + + +
+ +
+ +
+ +
+ + + + + + +
+ + {isLoading ? ( +
Loading details...
+ ) : filteredTransactions.length > 0 ? ( +
+
+ + + + + + + + + + + + + + + + + + {filteredTransactions.map((transaction) => ( + + + + + + + + + + + + + + ))} + +
+ Transaction Code + + MSISDN Reffer + + Transaction Type + TypeAmount + Pre Amount + + Post Amount + + Status Kind + + Date Time + Notes + Purpose +
+ {transaction.transaction_code} + + {transaction.msisdn_reff} + + {transaction.transaction_type?.name || 'N/A'} + {transaction.type} + {transaction.amount.toFixed(2)} + + {transaction.pre_amount.toFixed(2)} + + {transaction.post_amount.toFixed(2)} + + {transaction.category} + + {new Date(transaction.date).toLocaleString('id-ID', { + day: '2-digit', + month: 'short', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + })} + + {transaction.notes || '-'} + + {transaction.purpose || '-'} +
+
+
+ ) : ( +
No transaction data available
+ )} +
+
+ Showing {(currentPage - 1) * itemsPerPage + 1} to{' '} + {Math.min(currentPage * itemsPerPage, totalItems)} of {totalItems} entries +
+
+ + +
+ {Array.from({ length: Math.min(5, totalPages) }, (_, i) => { + let pageToShow; + if (totalPages <= 5) { + pageToShow = i + 1; + } else if (currentPage <= 3) { + pageToShow = i + 1; + } else if (currentPage >= totalPages - 2) { + pageToShow = totalPages - 4 + i; + } else { + pageToShow = currentPage - 2 + i; + } + + return ( + + ); + })} +
+ + +
+
+
+
+
+
+ ); +}; + +export default ShowDialog; diff --git a/src/pages/wallet/wallet-history/hooks/ManageWalletHistoryContext.tsx b/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx similarity index 97% rename from src/pages/wallet/wallet-history/hooks/ManageWalletHistoryContext.tsx rename to src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx index 629762a..ac3cc27 100644 --- a/src/pages/wallet/wallet-history/hooks/ManageWalletHistoryContext.tsx +++ b/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx @@ -250,14 +250,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } if (Array.isArray(filter)) { filter.forEach((f: any) => { if (f.id === 'msisdn' && f.value) { - filterParams.msisdn = { like: `%${f.value.toLowerCase()}%` }; - } - - if (f.id === 'CreatedAt' && f.value?.from && f.value?.to) { - filterParams.created_at = { - from: `${f.value.from} 00:00:00`, - to: `${f.value.to} 23:59:59` - }; + filterParams.msisdn = f.value; } if (f.id === 'id_wallet' && f.value) { diff --git a/src/pages/wallet/wallet-statement/hooks/useManageWalletStatementContext.tsx b/src/pages/wallet/wallet-statement/hooks/useManageWalletStatementContext.tsx new file mode 100644 index 0000000..dd7c6df --- /dev/null +++ b/src/pages/wallet/wallet-statement/hooks/useManageWalletStatementContext.tsx @@ -0,0 +1,13 @@ +import { useContext } from 'react'; +import { ManageWalletContext } from './ManageWalletStatementContext'; + + +const useManageStatementContext = () => { + const context = useContext(ManageWalletContext); + if (!context) { + throw new Error('useManageStatementContext must be used within a ManageStatementContextProvider'); + } + return context; +}; + +export { useManageStatementContext }; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index f053db3..1da4e34 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -41,7 +41,7 @@ import ProviderMaster from '@/pages/master/provider/ProviderMaster'; import ConversionMaster from '@/pages/master/conversion/ConversionMaster'; import RewardMaster from '@/pages/master/reward/RewardMaster'; import WalletRuleMaster from '@/pages/master/walletRule/WalletRuleMaster'; -import WalletHistory from '@/pages/wallet/wallet-history/WalletHistory'; +import WalletStatement from '@/pages/wallet/wallet-statement/WalletStatement'; import WalletMaster from '@/pages/master/wallet/WalletMaster'; import CurrencyMaster from '@/pages/master/currency/CurrencyMaster'; import FeedbackMemberMaster from '@/pages/members/feedback-member/FeedbackMember'; @@ -101,7 +101,7 @@ const AppRoutingSetup = (): ReactElement => { } /> - } /> + } /> } /> From b11fe62bd62311b37dfbd9c99102528783ba5f3a Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Thu, 22 May 2025 09:25:54 +0700 Subject: [PATCH 6/7] update filter in showdetailwalletdialog.tsx --- .../home/blocks/ShowDetailWalletDialog.tsx | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/pages/dashboards/home/blocks/ShowDetailWalletDialog.tsx b/src/pages/dashboards/home/blocks/ShowDetailWalletDialog.tsx index c4ec9ad..654817c 100644 --- a/src/pages/dashboards/home/blocks/ShowDetailWalletDialog.tsx +++ b/src/pages/dashboards/home/blocks/ShowDetailWalletDialog.tsx @@ -102,11 +102,26 @@ const ShowDetailWalletDialog: React.FC = ({ const handleApplyFilters = () => { const appliedFilters: any = {}; - if (dateRange.from) appliedFilters.date_from = dateRange.from+" 00:00:00"; - if (dateRange.to) appliedFilters.date_to = dateRange.to+" 23:59:59"; - if (selectedTransferType) appliedFilters.transaction_type_id = selectedTransferType; - if (selectedCategory) appliedFilters.category = selectedCategory; - if (searchValue) appliedFilters.transaction_code = searchValue; + if (dateRange.from && dateRange.to) { + const fromDate = new Date(`${dateRange.from}T00:00:00Z`); + const toDate = new Date(`${dateRange.to}T23:59:59Z`); + appliedFilters.date = { + from: fromDate.toISOString(), + to: toDate.toISOString(), + }; + } + + if (selectedTransferType) { + appliedFilters.transaction_type_id = selectedTransferType; + } + + if (selectedCategory) { + appliedFilters.category = selectedCategory; + } + + if (searchValue) { + appliedFilters.transaction_code = searchValue; + } setFilters(appliedFilters); }; @@ -207,7 +222,7 @@ const ShowDetailWalletDialog: React.FC = ({ with_deleted: false, order_field: "created_at", order_direction: 'DESC', - filter: filters + filter: JSON.stringify(filters) }); // console.log(filters); From 718fca4c76e70d729d00345e2512a00a52a079d7 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Thu, 22 May 2025 10:18:15 +0700 Subject: [PATCH 7/7] fix disbursement detail --- .../blocks/DetailTransaction.tsx | 291 +++++++++--------- 1 file changed, 153 insertions(+), 138 deletions(-) diff --git a/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx b/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx index b288d0a..81eeec5 100644 --- a/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx +++ b/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx @@ -94,66 +94,65 @@ const DetailTransaction = () => { } }, [showDetailDialog]); -const handleExport = async () => { - if (!selectedTransactionId || !transactionDetails) return; + const handleExport = async () => { + if (!selectedTransactionId || !transactionDetails) return; - setIsExporting(true); - try { - const response = await fetch( - `${API_URL}/transaction/export?id_disbursment=${selectedTransactionId}`, - { - method: 'GET', - headers: { - Authorization: `Bearer ${getAuth()?.access_token}` + setIsExporting(true); + try { + const response = await fetch( + `${API_URL}/transaction/export?id_disbursment=${selectedTransactionId}`, + { + method: 'GET', + headers: { + Authorization: `Bearer ${getAuth()?.access_token}` + } + } + ); + + if (!response.ok) { + throw new Error('Failed to fetch file'); + } + + const blob = await response.blob(); + const contentDisposition = response.headers.get('content-disposition'); + + const executionDate = transactionDetails.execution_date; + const formattedDate = executionDate + ? moment(executionDate).format('YYYYMMDD_HHmm') + : moment().format('YYYYMMDD_HHmm'); + + let filename = `transaction_${formattedDate}.xlsx`; + + if (contentDisposition) { + const filenameMatch = contentDisposition.match(/filename\*?=(?:UTF-8'')?"?([^;"\n]*)"?/); + if (filenameMatch && filenameMatch[1]) { + filename = decodeURIComponent(filenameMatch[1]); } } - ); - if (!response.ok) { - throw new Error('Failed to fetch file'); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + a.click(); + window.URL.revokeObjectURL(url); + + toast.success('Export successful'); + } catch (error) { + console.error('Error exporting transaction:', error); + toast.error('Failed to export transaction'); + } finally { + setIsExporting(false); } - - const blob = await response.blob(); - const contentDisposition = response.headers.get('content-disposition'); - - const executionDate = transactionDetails.execution_date; - const formattedDate = executionDate - ? moment(executionDate).format('YYYYMMDD_HHmm') - : moment().format('YYYYMMDD_HHmm'); - - let filename = `transaction_${formattedDate}.xlsx`; - - if (contentDisposition) { - const filenameMatch = contentDisposition.match(/filename\*?=(?:UTF-8'')?"?([^;"\n]*)"?/); - if (filenameMatch && filenameMatch[1]) { - filename = decodeURIComponent(filenameMatch[1]); - } - } - - const url = window.URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - a.click(); - window.URL.revokeObjectURL(url); - - toast.success('Export successful'); - } catch (error) { - console.error('Error exporting transaction:', error); - toast.error('Failed to export transaction'); - } finally { - setIsExporting(false); - } -}; - + }; return ( - + Transaction Details - +
{/* Summary Info */} {transactionDetails && ( @@ -213,7 +212,6 @@ const handleExport = async () => {
)} - {/* Log Table */}
{isLoading ? (
@@ -229,96 +227,113 @@ const handleExport = async () => {

Loading Logs Details...

) : ( - - - - - - - - - - - - - - - - - {transactionDetails?.log && transactionDetails.log.length > 0 ? ( - transactionDetails.log.map((log: any, index: number) => ( - - - - - - - - - - - + <> +
+ +
+
+
UsernameFullnameAmountStatusProcess DateInvoice NumberRemark 1Remark 2Remark 3Actions
- {log.customer?.username ?? 'Not Found'} - - {log.customer?.fullname ?? 'Not Found'} - {log.amount ?? '-'} - {renderStatusBadge(log.status) ?? '-'} - - {log.request_date && moment(log.request_date).isValid() - ? moment(log.request_date).format('DD/MM/YYYY HH:mm') - : '-'} - - {log.reference ?? '-'} - {log.remark_1 ?? '-'}{log.remark_2 ?? '-'}{log.remark_3 ?? '-'} - -
+ + + + + + + + + + + + - )) - ) : ( - - - - )} - -
UsernameFullnameAmountStatus + Process Date + + Invoice Number + Remark 1Remark 2Remark 3Actions
- No logs available -
+ + + {transactionDetails?.log && transactionDetails.log.length > 0 ? ( + transactionDetails.log.map((log: any, index: number) => ( + + + {log.customer?.username ?? 'Not Found'} + + + {log.customer?.fullname ?? 'Not Found'} + + + {log.amount ?? '-'} + + + {renderStatusBadge(log.status) ?? '-'} + + + {log.request_date && moment(log.request_date).isValid() + ? moment(log.request_date).format('DD/MM/YYYY HH:mm') + : '-'} + + + {log.reference ?? '-'} + + + {log.remark_1 ?? '-'} + + + {log.remark_2 ?? '-'} + + + {log.remark_3 ?? '-'} + + + + + + )) + ) : ( + + + No logs available + + + )} + + +
+ )}
- - {/* Export Button - Moved to bottom right after table */} -
- -
@@ -326,4 +341,4 @@ const handleExport = async () => { ); }; -export default DetailTransaction; \ No newline at end of file +export default DetailTransaction;