@accounter/client
Version:
Accounter client application
1 lines • 14.3 kB
JavaScript
import{s as e}from"./dist-C51EwTaa.js";import{i as t,n,o as r,t as i}from"./utils-DdVdMk8X.js";import{Io as a,Lo as o,R as s,Yn as c,_ as l,r as u,t as d}from"./error-handling-Dpfd9svJ.js";import{_t as f,a as p,c as m,d as h,dt as g,f as _,i as v,l as y,mt as b,n as x,o as S,p as C,r as w,s as T,t as E,u as D}from"./select-CrsvQyhZ.js";import{t as O}from"./pencil-i7-vyfzU.js";import{c as k,t as A}from"./button-Dzp2INW0.js";import{a as j,c as M,i as ee,o as te,r as ne,s as re,t as ie}from"./alert-dialog-f2YmJQwd.js";import{$r as ae,Mt as oe,St as se,Yr as ce,bt as N,cn as P,cr as F,dr as I,hi as L,lr as R,or as z,xt as B}from"./index-CL8-JoMZ.js";import{t as V}from"./page-layout-DoLDsSrs.js";import{t as H}from"./spinner-CIpm0zlo.js";var U=f(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]),W=e(r(),1),G=`addTag`,K=()=>{let[{fetching:e},t]=a(l);return{fetching:e,addTag:(0,W.useCallback)(async e=>{let n=`Error adding new tag [${e.tagName}]`,r=`${G}-${e.tagName}`;u.loading(`Adding tag`,{id:r});try{d(await t(e),n,r)&&u.success(`Success`,{id:r,description:`"${e.tagName}" tag was successfully added`})}catch(e){console.error(`${n}: ${e}`),u.error(`Error`,{id:r,description:n,duration:1e5,closeButton:!0})}},[t])}},q=t();function le({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`field-group`,className:i(`group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4`,e),...t})}var ue=k(`group/field data-[invalid=true]:text-red-500 flex w-full gap-3 dark:data-[invalid=true]:text-red-900`,{variants:{orientation:{vertical:[`flex-col [&>*]:w-full [&>.sr-only]:w-auto`],horizontal:[`flex-row items-center`,`[&>[data-slot=field-label]]:flex-auto`,`has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px has-[>[data-slot=field-content]]:items-start`],responsive:[`@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto flex-col [&>*]:w-full [&>.sr-only]:w-auto`,`@md/field-group:[&>[data-slot=field-label]]:flex-auto`,`@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px`]}},defaultVariants:{orientation:`vertical`}});function J({className:e,orientation:t=`vertical`,...n}){return(0,q.jsx)(`div`,{role:`group`,"data-slot":`field`,"data-orientation":t,className:i(ue({orientation:t}),e),...n})}function Y({className:e,...t}){return(0,q.jsx)(S,{"data-slot":`field-label`,className:i(`group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50`,`has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>[data-slot=field]]:p-4`,`has-data-[state=checked]:bg-gray-900/5 has-data-[state=checked]:border-gray-900 dark:has-data-[state=checked]:bg-gray-900/10 dark:has-data-[state=checked]:bg-gray-50/5 dark:has-data-[state=checked]:border-gray-50 dark:dark:has-data-[state=checked]:bg-gray-50/10`,e),...t})}function X({open:e,onOpenChange:t,tag:r,onSave:i,isSaving:a}){let[c,l]=(0,W.useState)(``),[u,d]=(0,W.useState)(null),[{data:f,fetching:g},b]=o({query:s,pause:!0});(0,W.useEffect)(()=>{e&&b()},[e,b]);let S=(0,W.useMemo)(()=>f?.allTags??[],[f]);(0,W.useEffect)(()=>{e&&(r?(l(r.name),d(r.parent?.id??null)):(l(``),d(null)))},[r,e]);let O=async()=>{c.trim()&&!a&&(await i(c.trim(),u),t(!1))},k=(0,W.useMemo)(()=>{if(!r)return S;let e=new Set,t=[r.id],n=S.reduce((e,t)=>{if(t.parent?.id){let n=e.get(t.parent.id)??[];n.push(t.id),e.set(t.parent.id,n)}return e},new Map);for(;t.length>0;){let r=t.shift();if(!e.has(r)){e.add(r);let i=n.get(r)??[];t.push(...i)}}return S.filter(t=>!e.has(t.id))},[S,r]),j=n(c);return(0,q.jsx)(m,{open:e,onOpenChange:a?void 0:t,children:(0,q.jsx)(y,{className:`max-w-[calc(100vw-2rem)] sm:max-w-lg`,children:g&&S.length===0?(0,q.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-10 gap-3`,children:[(0,q.jsx)(H,{className:`size-8`}),(0,q.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`Loading tags...`})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsxs)(_,{children:[(0,q.jsx)(C,{children:r?`Edit Tag`:`Create Tag`}),(0,q.jsx)(D,{children:r?`Update the tag name and parent category.`:`Add a new tag to organize your finances.`})]}),(0,q.jsxs)(le,{children:[(0,q.jsxs)(J,{children:[(0,q.jsx)(Y,{htmlFor:`tag-name`,children:`Name`}),(0,q.jsx)(T,{id:`tag-name`,value:c,onChange:e=>l(e.target.value),placeholder:`Enter tag name`,dir:j?`rtl`:`ltr`,disabled:a,onKeyDown:e=>{e.key===`Enter`&&O()}})]}),(0,q.jsxs)(J,{children:[(0,q.jsx)(Y,{htmlFor:`tag-parent`,children:`Parent Tag (optional)`}),(0,q.jsxs)(E,{value:u??`none`,onValueChange:e=>d(e===`none`?null:e),disabled:a,children:[(0,q.jsx)(v,{id:`tag-parent`,children:(0,q.jsx)(p,{placeholder:`Select parent tag`})}),(0,q.jsxs)(x,{children:[(0,q.jsx)(w,{value:`none`,children:`No Parent`}),k.map(e=>{let t=e.namePath&&e.namePath.length>0?`${e.namePath.join(` / `)} / ${e.name}`:e.name;return(0,q.jsx)(w,{value:e.id,dir:n(e.name)?`rtl`:`ltr`,children:t},e.id)})]})]})]})]}),(0,q.jsxs)(h,{className:`flex-col gap-2 sm:flex-row`,children:[(0,q.jsx)(A,{variant:`outline`,onClick:()=>t(!1),className:`w-full sm:w-auto`,disabled:a,children:`Cancel`}),(0,q.jsx)(A,{onClick:O,disabled:!c.trim()||a,className:`w-full sm:w-auto`,children:a?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(H,{className:`size-4 me-2`}),`Saving...`]}):r?`Save Changes`:`Create Tag`})]})]})})})}function Z({onDone:e,children:t}){let[n,r]=(0,W.useState)(!1),[i,a]=(0,W.useState)(!1),{addTag:o}=K(),s=(0,W.useCallback)(async(t,n)=>{a(!0);try{await o({tagName:t,parentTag:n}),await e()}finally{a(!1)}},[o,e]);return(0,q.jsxs)(q.Fragment,{children:[t?(0,q.jsx)(A,{asChild:!0,onClick:()=>r(!0),children:t}):(0,q.jsxs)(A,{onClick:()=>r(!0),className:`w-full sm:w-auto`,children:[(0,q.jsx)(g,{className:`size-4 me-2`}),`Create Tag`]}),(0,q.jsx)(X,{open:n,onOpenChange:r,tag:null,onSave:s,isSaving:i})]})}function de({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`empty`,className:i(`flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12`,e),...t})}var fe=k(`mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0`,{variants:{variant:{default:`bg-transparent`,icon:`bg-gray-100 text-gray-950 flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6 dark:bg-gray-800 dark:text-gray-50`}},defaultVariants:{variant:`default`}});function pe({className:e,variant:t=`default`,...n}){return(0,q.jsx)(`div`,{"data-slot":`empty-icon`,"data-variant":t,className:i(fe({variant:t,className:e})),...n})}function me({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`empty-title`,className:i(`text-lg font-medium tracking-tight`,e),...t})}function Q({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`empty-description`,className:i(`text-gray-500 [&>a:hover]:text-gray-900 text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4 dark:text-gray-400 dark:[&>a:hover]:text-gray-50`,e),...t})}function he({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`empty-content`,className:i(`flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm`,e),...t})}var ge=`deleteTag`,_e=()=>{let[{fetching:e},t]=a(c);return{fetching:e,deleteTag:(0,W.useCallback)(async e=>{let n=`Error deleting new tag [${e.name}]`,r=`${ge}-${e.tagId}`;u.loading(`Deleting tag [${e.name}]`,{id:r});try{d(await t(e),n,r)&&u.success(`Tag Deleted`,{id:r,description:`[${e.name}] tag was successfully removed`})}catch(e){console.error(`${n}: ${e}`),u.error(`Error`,{id:r,description:n,duration:1e5,closeButton:!0})}},[t])}};function ve({open:e,onOpenChange:t,tag:r,onConfirm:i,isDeleting:a}){if(!r)return null;let o=n(r.name);return(0,q.jsx)(ie,{open:e,onOpenChange:a?void 0:t,children:(0,q.jsxs)(ee,{className:`max-w-[calc(100vw-2rem)] sm:max-w-lg`,children:[(0,q.jsxs)(re,{children:[(0,q.jsx)(M,{children:`Delete Tag`}),(0,q.jsxs)(j,{children:[`Are you sure you want to delete the tag`,` `,(0,q.jsxs)(`span`,{className:`font-semibold text-foreground`,dir:o?`rtl`:`ltr`,children:[`"`,r.name,`"`]}),`? This action cannot be undone.`]})]}),(0,q.jsxs)(te,{className:`flex-col gap-2 sm:flex-row`,children:[(0,q.jsx)(ne,{className:`w-full sm:w-auto`,disabled:a,children:`Cancel`}),(0,q.jsx)(A,{onClick:i,disabled:a,variant:`destructive`,className:`w-full sm:w-auto`,children:a?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(H,{className:`size-4 me-2`}),`Deleting...`]}):`Delete`})]})]})})}function ye({tag:e,depth:t,hasChildren:r,isCollapsed:a,onToggleCollapse:o,onEdit:s,onDelete:c}){let l=n(e.name);return(0,q.jsxs)(`div`,{className:i(`group flex items-center justify-between gap-2 px-3 py-3 border-b border-border`,`hover:bg-secondary/50 transition-colors`,`sm:px-4`),children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0 flex-1`,style:{paddingInlineStart:`${t*20}px`},children:[r?(0,q.jsx)(`button`,{type:`button`,onClick:()=>o(e.id),className:`p-0.5 rounded hover:bg-secondary transition-colors shrink-0`,"aria-expanded":!a,"aria-label":a?`Expand`:`Collapse`,children:(0,q.jsx)(b,{className:i(`size-4 text-muted-foreground transition-transform rtl:rotate-180`,!a&&`rotate-90 rtl:rotate-90`)})}):t>0?(0,q.jsx)(`span`,{className:`size-4 shrink-0`,"aria-hidden":`true`}):null,(0,q.jsx)(`span`,{className:i(`text-foreground font-medium truncate`,l&&`text-right`),dir:l?`rtl`:`ltr`,children:e.name}),e.namePath&&e.namePath.length>0&&(0,q.jsxs)(`span`,{className:`text-muted-foreground text-sm hidden sm:inline truncate shrink-0`,children:[`(`,e.namePath.join(` / `),`)`]})]}),(0,q.jsxs)(z,{children:[(0,q.jsx)(I,{asChild:!0,children:(0,q.jsxs)(A,{variant:`ghost`,size:`sm`,className:`opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity shrink-0`,children:[(0,q.jsx)(L,{className:`size-4`}),(0,q.jsx)(`span`,{className:`sr-only`,children:`Actions`})]})}),(0,q.jsxs)(F,{align:`end`,children:[(0,q.jsxs)(R,{onClick:()=>s(e),children:[(0,q.jsx)(O,{className:`size-4 me-2`}),`Edit`]}),(0,q.jsxs)(R,{onClick:()=>c(e),className:`text-destructive focus:text-destructive`,children:[(0,q.jsx)(ce,{className:`size-4 me-2`}),`Delete`]})]})]})]})}function be(e){let t=new Map,n=[];e.map(e=>{t.set(e.id,{tag:e,children:[]})}),e.map(e=>{let r=t.get(e.id);if(e.parent){let i=t.get(e.parent.id);i?i.children.push(r):n.push(r)}else n.push(r)});let r=e=>e.sort((e,t)=>e.tag.name.localeCompare(t.tag.name)).map(e=>({...e,children:r(e.children)}));return r(n)}function $(e,t,n=0){let r=[];return e.map(e=>{let i=e.children.length>0;r.push({tag:e.tag,depth:n,hasChildren:i}),i&&!t.has(e.tag.id)&&r.push(...$(e.children,t,n+1))}),r}function xe({search:e,allTags:t,onChange:n}){let[r,i]=(0,W.useState)(new Set),[a,o]=(0,W.useState)(!1),[s,c]=(0,W.useState)(!1),[l,u]=(0,W.useState)(null),[d,f]=(0,W.useState)(!1),[p,m]=(0,W.useState)(!1),{addTag:h}=K(),{deleteTag:_}=_e(),{updateTag:v}=oe(),y=(0,W.useMemo)(()=>{if(!e.trim())return t;let n=e.toLowerCase();return t.filter(e=>e.name.toLowerCase().includes(n)||e.namePath?.some(e=>e.toLowerCase().includes(n)))},[t,e]),b=(0,W.useMemo)(()=>$(be(y),r),[y,r]);(0,W.useEffect)(()=>{e.trim()&&i(new Set)},[e]);let x=(0,W.useCallback)(e=>{i(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),S=(0,W.useCallback)(e=>{u(e),o(!0)},[]),C=(0,W.useCallback)(e=>{u(e),c(!0)},[]),w=(0,W.useCallback)(async(e,t)=>{f(!0);try{l?await v({tagId:l.id,fields:{name:e,parentId:t}}):await h({tagName:e,parentTag:t}),await n(),u(null)}finally{f(!1)}},[h,l,n,v]),T=(0,W.useCallback)(async()=>{if(l){m(!0);try{await _({tagId:l.id,name:l.name}),await n(),u(null),c(!1)}finally{m(!1)}}},[_,l,n]);return(0,q.jsxs)(`div`,{className:`min-h-screen bg-background`,children:[(0,q.jsxs)(`div`,{className:`max-w-4xl mx-auto px-4 py-6 sm:py-8`,children:[(0,q.jsx)(`div`,{className:`rounded-lg border border-border bg-card overflow-hidden`,children:b.length>0?b.map(({tag:e,depth:t,hasChildren:n})=>(0,q.jsx)(ye,{tag:e,depth:t,hasChildren:n,isCollapsed:r.has(e.id),onToggleCollapse:x,onEdit:S,onDelete:C},e.id)):(0,q.jsxs)(de,{className:`py-8 sm:py-12`,children:[(0,q.jsx)(pe,{children:(0,q.jsx)(U,{className:`size-8 sm:size-10 text-muted-foreground`})}),(0,q.jsx)(me,{children:e?`No tags found`:`No tags yet`}),(0,q.jsx)(Q,{children:e?`Try adjusting your search query.`:`Create your first tag to start organizing your finances.`}),!e&&(0,q.jsx)(he,{children:(0,q.jsx)(Z,{onDone:n,children:(0,q.jsxs)(A,{children:[(0,q.jsx)(g,{className:`size-4 me-2`}),`Create Tag`]})})})]})}),t.length>0&&(0,q.jsxs)(`p`,{className:`text-muted-foreground text-sm mt-4 text-center`,children:[y.length,` of `,t.length,` tag`,t.length===1?``:`s`]})]}),(0,q.jsx)(X,{open:a,onOpenChange:o,tag:l,onSave:w,isSaving:d}),(0,q.jsx)(ve,{open:s,onOpenChange:c,tag:l,onConfirm:T,isDeleting:p})]})}var Se=()=>{let[e,t]=(0,W.useState)(``),{setFiltersContext:n}=(0,W.useContext)(P);(0,W.useEffect)(()=>{n(null)},[n]);let[{data:r,fetching:i},a]=o({query:s}),c=(0,W.useMemo)(()=>r?.allTags??[],[r]);return i&&c.length===0?(0,q.jsx)(`div`,{className:`min-h-screen bg-background flex items-center justify-center`,children:(0,q.jsxs)(`div`,{className:`flex flex-col items-center gap-3`,children:[(0,q.jsx)(H,{className:`size-8`}),(0,q.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`Loading tags...`})]})}):(0,q.jsx)(V,{title:`Tags`,description:`Manage your charges tags.`,headerActions:(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsxs)(N,{className:`max-w-xs`,children:[(0,q.jsx)(se,{placeholder:`Search tags...`,value:e,onChange:e=>t(e.target.value),className:`ps-10`}),(0,q.jsx)(B,{children:(0,q.jsx)(ae,{})})]}),(0,q.jsx)(Z,{onDone:async()=>{await a()},children:(0,q.jsxs)(A,{className:`w-full sm:w-auto`,children:[(0,q.jsx)(g,{className:`size-4 me-2`}),`Create Tag`]})})]}),children:(0,q.jsx)(xe,{search:e,allTags:c,onChange:async()=>{await a()}})})};export{Se as TagsManager};