@accounter/client
Version:
Accounter client application
1 lines โข 13.3 kB
JavaScript
import{s as e}from"./dist-ypP48_Ax.js";import{i as t,o as n,t as r}from"./utils-CbS-oR5I.js";import{S as i}from"./routes-D0AKaVmS.js";import{n as a}from"./loader-circle-CfW9jOIr.js";import{Yn as o,ct as s,dt as c,fr as l,i as u,o as d,q as f,s as p,t as m}from"./common-3blB_OGJ.js";import{a as h,i as g,mt as ee,n as _,o as v,r as y,s as b,t as x}from"./select-Bp1lD5cE.js";import{t as S}from"./circle-check-Cq288m4n.js";import{t as C}from"./circle-slash-P6DApRft.js";import{t as w}from"./info-CxIWs3QN.js";import{n as T,t as E}from"./panel-left-open-C3lw_jDm.js";import{t as D}from"./button-DUNsVBiu.js";import{i as O,n as k,r as A,t as te}from"./accordion-Cpzlrsi0.js";import{Ul as ne,Zc as j}from"./table-B6QCIQQv.js";import{a as re,n as M,o as N,t as P}from"./card-DR4aRSHr.js";import{ls as ie,nn as F,rn as I,tn as L,un as ae}from"./graphql-lcoKwSC9.js";import{n as R,r as oe,t as z}from"./alert-55QsYEfR.js";import{t as B}from"./page-layout-Dg61gTWe.js";var V=a(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),H=a(`skip-forward`,[[`path`,{d:`M21 4v16`,key:`7j8fe9`}],[`path`,{d:`M6.029 4.285A2 2 0 0 0 3 6v12a2 2 0 0 0 3.029 1.715l9.997-5.998a2 2 0 0 0 .003-3.432z`,key:`zs4d6`}]]),U=e(n(),1);function W(e){let[t,n]=(0,U.useState)({}),[r,i]=(0,U.useState)(null),a=(0,U.useMemo)(()=>{let n={};for(let r of e)n[r.id]=t[r.id]??`pending`;return n},[e,t]),o=(0,U.useMemo)(()=>e.findIndex(e=>(t[e.id]??`pending`)===`pending`),[e,t]),s=o===-1?e.length:o,c=r===null?-1:e.findIndex(e=>e.id===r),l=c===-1?s:c,u=(0,U.useCallback)(n=>{!e.some(e=>e.id===n)||(t[n]??`pending`)===`matched`||i(n)},[e,t]),d=(0,U.useCallback)(e=>{n(t=>({...t,[e]:`skipped`})),i(null)},[]),f=(0,U.useCallback)((e,t)=>{t&&(n(t=>({...t,[e]:`matched`})),i(null))},[]);return{items:e,activeIndex:l,activeItem:e[l]??null,isDone:s>=e.length,statusById:a,selectItem:u,skipItem:d,acceptItemStatus:f}}var G=t(),K=({suggestions:e,selectedIndex:t,onSelect:n})=>e.length<=1?null:(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-semibold text-gray-500`,children:`Alternative Suggestions`}),(0,G.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.map((e,r)=>(0,G.jsxs)(D,{variant:r===t?`default`:`outline`,size:`sm`,onClick:()=>n(r),"aria-pressed":r===t,children:[(0,G.jsxs)(`span`,{className:`font-semibold`,children:[`#`,r+1]}),(0,G.jsx)(`span`,{className:`max-w-40 truncate`,children:e.label}),(0,G.jsxs)(`span`,{className:`text-xs opacity-70`,children:[Math.round(e.confidenceScore*100),`%`]})]},e.chargeId))})]});function q(e){let t=e.minDocumentsDate??e.minEventDate??e.minDebitDate;return t?ne(new Date(t),`dd/MM/yy`):void 0}function J(e){return e.counterparty?.name??e.userDescription??`Unknown charge`}function Y({label:e,value:t}){return t?(0,G.jsxs)(`div`,{className:`flex flex-col`,children:[(0,G.jsx)(`span`,{className:`text-xs text-gray-500`,children:e}),(0,G.jsx)(`span`,{className:`text-sm font-medium`,children:t})]}):null}var X=({charge:e,confidenceScore:t,title:n})=>{let r=e.additionalDocuments??[],i=e.transactions??[],a=e.miscExpenses??[],o=r.find(e=>e.image),s=[...new Set(r.map(e=>e.documentType).filter(Boolean))].join(`, `),c=i.length>0||a.length>0;return(0,G.jsxs)(P,{"data-testid":`charge-detail-card`,children:[(0,G.jsxs)(re,{className:`flex flex-row items-center justify-between`,children:[(0,G.jsx)(N,{className:`text-base`,children:n}),t!=null&&(0,G.jsx)(`div`,{className:`flex items-center gap-2`,"aria-label":`Match confidence score: ${Math.round(t*100)}%`,children:(0,G.jsx)(m,{value:Math.round(t*100),size:`sm`})})]}),(0,G.jsxs)(M,{className:`flex flex-col gap-4`,children:[(0,G.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,G.jsx)(Y,{label:`Date`,value:q(e)}),(0,G.jsx)(Y,{label:`Amount`,value:e.totalAmount?.formatted}),(0,G.jsx)(Y,{label:`Counterparty`,value:e.counterparty?.name}),(0,G.jsx)(Y,{label:`Document type`,value:s})]}),(0,G.jsx)(Y,{label:`Description`,value:e.userDescription}),o?.image?(0,G.jsx)(`a`,{href:o.file?.toString()??o.image.toString(),target:`_blank`,rel:`noreferrer`,children:(0,G.jsx)(`img`,{src:o.image.toString(),alt:`Document preview`,className:`max-h-56 w-auto rounded-md border object-contain`})}):(0,G.jsx)(`p`,{className:`text-xs text-gray-400`,children:`No document preview`}),c&&(0,G.jsx)(te,{type:`single`,collapsible:!0,children:(0,G.jsxs)(A,{value:`more-details`,children:[(0,G.jsx)(O,{className:`text-sm`,children:`More Details`}),(0,G.jsxs)(k,{className:`flex flex-col gap-3`,children:[i.length>0&&(0,G.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,G.jsx)(`span`,{className:`text-xs font-semibold text-gray-500`,children:`Transactions`}),(0,G.jsx)(`ul`,{className:`flex flex-col gap-1`,children:i.map(e=>(0,G.jsxs)(`li`,{className:`flex justify-between gap-2 text-sm`,children:[(0,G.jsxs)(`span`,{className:`truncate`,children:[e.eventDate,` ยท `,e.sourceDescription]}),(0,G.jsx)(`span`,{className:`shrink-0 font-medium`,children:e.amount.formatted})]},e.id))})]}),a.length>0&&(0,G.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,G.jsx)(`span`,{className:`text-xs font-semibold text-gray-500`,children:`Misc Expenses`}),(0,G.jsx)(`ul`,{className:`flex flex-col gap-1`,children:a.map(e=>(0,G.jsxs)(`li`,{className:`flex justify-between gap-2 text-sm`,children:[(0,G.jsx)(`span`,{className:`truncate`,children:e.description??`Misc expense`}),(0,G.jsx)(`span`,{className:`shrink-0 font-medium`,children:e.amount.formatted})]},e.id))})]})]})]})})]})]})},Z={businessId:null,fromDate:null,toDate:null,mode:null,sortBy:I.ByDate},se=[`mode`,`fromDate`,`toDate`,`businessId`,`sortBy`],ce=Object.values(F),le=Object.values(I);function ue(e){let t=e.get(`mode`),n=ce.includes(t)?t:Z.mode,r=e.get(`sortBy`),i=le.includes(r)?r:Z.sortBy;return{businessId:e.get(`businessId`)||null,fromDate:e.get(`fromDate`)||null,toDate:e.get(`toDate`)||null,mode:n,sortBy:i}}function Q(e){let t={};return e.mode&&(t.mode=e.mode),e.fromDate&&(t.fromDate=e.fromDate),e.toDate&&(t.toDate=e.toDate),e.businessId&&(t.businessId=e.businessId),e.sortBy!==Z.sortBy&&(t.sortBy=e.sortBy),t}var $=`ALL`,de=({filters:e,onFiltersChange:t})=>{let{selectableBusinesses:n,fetching:r}=c(),i=n=>{t({...e,...n})};return(0,G.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,G.jsxs)(`div`,{className:`flex flex-wrap items-end gap-4`,children:[(0,G.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,G.jsx)(v,{htmlFor:`charge-matching-mode`,children:`Mode`}),(0,G.jsxs)(x,{value:e.mode??$,onValueChange:e=>i({mode:e===$?null:e}),children:[(0,G.jsx)(g,{id:`charge-matching-mode`,className:`w-44`,children:(0,G.jsx)(h,{placeholder:`All`})}),(0,G.jsxs)(_,{children:[(0,G.jsx)(y,{value:$,children:`All`}),(0,G.jsx)(y,{value:F.DocBase,children:`Doc Base`}),(0,G.jsx)(y,{value:F.TransactionBase,children:`Transaction Base`})]})]})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,G.jsx)(v,{htmlFor:`charge-matching-from-date`,children:`From`}),(0,G.jsx)(b,{id:`charge-matching-from-date`,type:`date`,className:`w-40`,max:e.toDate??void 0,value:e.fromDate??``,onChange:e=>i({fromDate:e.target.value||null})})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,G.jsx)(v,{htmlFor:`charge-matching-to-date`,children:`To`}),(0,G.jsx)(b,{id:`charge-matching-to-date`,type:`date`,className:`w-40`,min:e.fromDate??void 0,value:e.toDate??``,onChange:e=>i({toDate:e.target.value||null})})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-1 min-w-52`,children:[(0,G.jsx)(v,{children:`Business`}),(0,G.jsx)(s,{data:n,disabled:r,placeholder:`All businesses`,value:e.businessId,onChange:e=>i({businessId:e})})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-1 ml-auto`,children:[(0,G.jsx)(v,{children:`Sort by`}),(0,G.jsx)(u,{value:e.sortBy,onValueChange:e=>i({sortBy:e}),children:(0,G.jsxs)(d,{children:[(0,G.jsx)(p,{value:I.ByDate,children:`Date`}),(0,G.jsx)(p,{value:I.ByScore,children:`Match Score`})]})})]})]}),e.sortBy===I.ByScore&&(0,G.jsxs)(z,{children:[(0,G.jsx)(w,{className:`size-4`}),(0,G.jsx)(R,{children:`Note: Score-based sorting currently evaluates only the 100 most recent unmatched charges.`})]})]})};function fe({status:e}){switch(e){case`matched`:return(0,G.jsx)(S,{className:`size-4 shrink-0 text-green-600`,"aria-label":`Matched`});case`skipped`:return(0,G.jsx)(C,{className:`size-4 shrink-0 text-gray-400`,"aria-label":`Skipped`});default:return(0,G.jsx)(V,{className:`size-4 shrink-0 text-gray-300`,"aria-label":`Pending`})}}var pe=({items:e,statusById:t,activeId:n,collapsed:i,onToggleCollapsed:a,onSelectItem:s})=>(0,G.jsxs)(`div`,{className:r(`flex flex-col gap-2 border-r pr-3 transition-all`,i?`w-10`:`w-72 shrink-0`),children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[!i&&(0,G.jsx)(`h3`,{className:`text-sm font-semibold`,children:`Awaiting Matches`}),(0,G.jsx)(D,{variant:`ghost`,size:`icon`,onClick:a,"aria-label":i?`Show sidebar`:`Hide sidebar`,children:i?(0,G.jsx)(E,{className:`size-4`}):(0,G.jsx)(T,{className:`size-4`})})]}),!i&&(0,G.jsx)(o,{className:`h-[calc(100vh-20rem)]`,children:(0,G.jsxs)(`ul`,{className:`flex flex-col gap-1`,children:[e.map(e=>{let i=t[e.id]??`pending`;return(0,G.jsx)(`li`,{children:(0,G.jsxs)(`button`,{type:`button`,disabled:i===`matched`,onClick:()=>s(e.id),"aria-current":e.id===n?`true`:void 0,className:r(`flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors`,i!==`matched`&&`hover:bg-accent/60`,e.id===n&&`bg-accent`,i===`skipped`&&`opacity-50`,i===`matched`&&`cursor-not-allowed opacity-60`),children:[(0,G.jsx)(fe,{status:i}),(0,G.jsxs)(`div`,{className:`flex min-w-0 flex-col`,children:[(0,G.jsx)(`span`,{className:`truncate font-medium`,children:e.title}),(0,G.jsx)(`span`,{className:`truncate text-xs text-gray-500`,children:[e.subtitle,e.amount].filter(Boolean).join(` ยท `)})]})]})},e.id)}),e.length===0&&(0,G.jsx)(`li`,{className:`px-2 py-1.5 text-sm text-gray-500`,children:`No charges awaiting match`})]})})]}),me=()=>{let[e,t]=i(),n=(0,U.useMemo)(()=>ue(e),[e]),r=(0,U.useCallback)(e=>{t(t=>{let n=new URLSearchParams(t),r=Q(e);for(let e of se){let t=r[e];t==null?n.delete(e):n.set(e,t)}return n},{replace:!0})},[t]),[a,o]=(0,U.useState)(!1),[{data:s,fetching:c,error:u}]=ie({query:ae,variables:{limit:20,offset:0,businessId:n.businessId,fromDate:n.fromDate,toDate:n.toDate,mode:n.mode,sortBy:n.sortBy}}),d=(0,U.useMemo)(()=>(s?.chargesAwaitingMatchQueue.baseCharges??[]).map(e=>{let t=j(L,e.baseCharge);return{id:t.id,baseCharge:t,suggestions:e.suggestions}}),[s]),p=W(d),m=(0,U.useMemo)(()=>d.map(e=>({id:e.id,title:J(e.baseCharge),subtitle:q(e.baseCharge),amount:e.baseCharge.totalAmount?.formatted})),[d]),h=s?.chargesAwaitingMatchQueue.totalCount??0,{activeItem:g,selectItem:_,skipItem:v,acceptItemStatus:y}=p,[b,x]=(0,U.useState)(null),S=b&&b.itemId===g?.id?b.index:0,C=g?.suggestions[S],w=C?j(L,C.charge):null,T=(0,U.useMemo)(()=>(g?.suggestions??[]).map(e=>({chargeId:e.chargeId,confidenceScore:e.confidenceScore,label:J(j(L,e.charge))})),[g]),{mergeCharges:E,fetching:O}=f(),k=(0,U.useCallback)(()=>{g&&v(g.id)},[g,v]),A=(0,U.useCallback)(async()=>{if(!g||!C)return;let e=await E({baseChargeID:g.id,chargeIdsToMerge:[C.chargeId]});y(g.id,!!e)},[g,C,E,y]);return(0,G.jsxs)(B,{title:`Charge Matching`,description:`Review and merge suggested charge matches, one by one.`,children:[(0,G.jsx)(de,{filters:n,onFiltersChange:r}),u&&(0,G.jsxs)(z,{variant:`destructive`,children:[(0,G.jsx)(oe,{children:`Failed to load the matching queue`}),(0,G.jsx)(R,{children:u.message})]}),c?(0,G.jsxs)(`div`,{className:`flex gap-4`,children:[(0,G.jsx)(l,{className:`h-96 w-72`}),(0,G.jsx)(l,{className:`h-96 flex-1`})]}):u?null:(0,G.jsxs)(`div`,{className:`flex gap-4`,children:[(0,G.jsx)(pe,{items:m,statusById:p.statusById,activeId:g?.id??null,collapsed:a,onToggleCollapsed:()=>o(e=>!e),onSelectItem:_}),(0,G.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-4`,children:[(0,G.jsxs)(`p`,{className:`text-sm text-gray-500`,children:[`Showing `,d.length,` of `,h,` charges awaiting match`]}),(0,G.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 lg:grid-cols-2`,children:[g?(0,G.jsx)(X,{charge:g.baseCharge,title:`Base Charge`}):(0,G.jsxs)(`section`,{className:`rounded-lg border p-4`,children:[(0,G.jsx)(`h3`,{className:`mb-2 text-sm font-semibold text-gray-500`,children:`Base Charge`}),(0,G.jsx)(`p`,{className:`text-sm text-gray-500`,children:d.length===0?`No charges awaiting match.`:`Queue completed ๐`})]}),w?(0,G.jsx)(X,{charge:w,title:`Suggested Match`,confidenceScore:C?.confidenceScore}):(0,G.jsxs)(`section`,{className:`rounded-lg border p-4`,children:[(0,G.jsx)(`h3`,{className:`mb-2 text-sm font-semibold text-gray-500`,children:`Suggested Match`}),(0,G.jsx)(`p`,{className:`text-sm text-gray-500`,children:g?`No suggestions for this charge.`:`โ`})]})]}),g&&(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsxs)(D,{onClick:A,disabled:!C||O,children:[(0,G.jsx)(ee,{className:`size-4`}),`Accept`]}),(0,G.jsxs)(D,{variant:`outline`,onClick:k,disabled:O,children:[(0,G.jsx)(H,{className:`size-4`}),`Skip`]})]}),(0,G.jsx)(K,{suggestions:T,selectedIndex:S,onSelect:e=>g&&x({itemId:g.id,index:e})})]})]})]})};export{me as ChargeMatchingReviewScreen};