+ Date + {date || isAddingDate ? ( + setStatusMessage('Editing...')} + onChange={(e) => setDate(e.target.value)} + onBlur={onDateBlur} + /> + ) : ( + + )} +
+ +Do you really want to delete this task?
diff --git a/src/components/task-item/task-item.module.css b/src/components/task-item/task-item.module.css index af3d022..074cbbf 100644 --- a/src/components/task-item/task-item.module.css +++ b/src/components/task-item/task-item.module.css @@ -7,7 +7,6 @@ align-items: center; gap: var(--space-xs) var(--space-m); position: relative; - overflow: hidden; } .taskCost { @@ -23,7 +22,8 @@ .costInput, .description, .costDisplay, -.hours { +.hours, +.dateInput { transition: border-color 0.2s; padding: var(--space-xs); border: 1px dashed transparent; @@ -31,20 +31,34 @@ } .task:not(.invoicingActive):hover .description, -.task:not(.invoicingActive):hover .taskCostHoverable .costDisplay, +.task:not(.invoicingActive):hover .costDisplay, .task:not(.invoicingActive):hover .hours, -.task:not(.invoicingActive):hover .costInput { +.task:not(.invoicingActive):hover .costInput, +.task:not(.invoicingActive):hover .dateInput { border-color: var(--c-beige); } .task:not(.invoicingActive) .description:focus, .task:not(.invoicingActive) .hours:focus, -.task:not(.invoicingActive) .costInput:focus { +.task:not(.invoicingActive) .costDisplay:focus, +.task:not(.invoicingActive) .costInput:focus, +.task:not(.invoicingActive) .dateInput:focus { border-color: var(--c-midnight-green); border-style: solid; outline: none; } +.categoryInput { + padding: var(--space-xs); + border: 1px solid var(--bg-accent-border); + border-radius: var(--border-radius-small); + outline: none; +} + +.categoryInput:focus { + border-color: var(--c-midnight-green); +} + .costInput { position: absolute; top: 0; @@ -119,3 +133,96 @@ display: flex; gap: var(--space-m); } + +.taskMeta { + display: flex; + flex-wrap: wrap; + gap: var(--space-s); + align-items: center; + grid-column: 1 / -1; +} + +.categoryWrapper { + padding-left: var(--space-xs); +} + +.addDateButton { + margin-left: var(--space-xs); +} + +.categoriesDisplay { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--space-xs); +} + +.pill { + display: inline-flex; + align-items: center; + gap: 0.35em; + font-size: var(--step--1); + font-weight: var(--weight-semibold); + padding: 0.2em 0.4em 0.2em 0.75em; + border-radius: 100px; + background: var(--c-beige); + color: var(--c-black); + white-space: nowrap; +} + +.remove { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.2em; + height: 1.2em; + border-radius: 50%; + line-height: 1; + color: inherit; + transition: background-color 0.2s; +} + +.remove:hover { + background-color: rgba(0, 0, 0, 0.1); +} + +.categoryToggle { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.5em; + height: 1.5em; + border-radius: 50%; + color: var(--c-gray-dark); + transition: + background-color 0.2s, + color 0.2s; +} + +.categoryToggle svg { + width: 0.9em; + height: 0.9em; +} + +.categoryToggle:hover { + background-color: var(--c-beige-transparent); + color: var(--c-black); +} + +.addButton { + display: inline-flex; + align-items: center; + gap: 0.35em; + font-size: var(--step--1); + color: var(--c-gray-dark); + transition: color 0.2s; +} + +.addButton:hover { + color: var(--c-black); +} + +.addButton svg { + width: 0.9em; + height: 0.9em; +} diff --git a/src/contexts/CategoryContext.tsx b/src/contexts/CategoryContext.tsx new file mode 100644 index 0000000..2e50d46 --- /dev/null +++ b/src/contexts/CategoryContext.tsx @@ -0,0 +1,106 @@ +// contexts/CategoryContext.tsx +'use client'; + +import { RecordModel } from 'pocketbase'; +import pb from '@/lib/pocketbase'; +import { + ReactNode, + createContext, + useContext, + useEffect, + useRef, + useState, +} from 'react'; +import { useAuth } from '@/contexts/AuthContext'; +import { Category } from '@/types'; + +interface CategoryContextType { + areCategoriesLoaded: boolean; + categories: Category[]; + getOrCreateCategory: (name: string) => Promise