feat: implement archiving functionality for counters and update related logic
This commit is contained in:
@@ -7,6 +7,7 @@ export interface Counter {
|
||||
image_path: string | null;
|
||||
group_id: number | null;
|
||||
order_index: number;
|
||||
archived_at?: number | null;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@@ -69,7 +70,7 @@ export default function CounterCard({ counter, onIncrement, onDecrement, onEdit,
|
||||
<div className="flex items-center bg-ctp-surface1 rounded-2xl overflow-hidden">
|
||||
<button
|
||||
onClick={() => onDecrement(counter.id)}
|
||||
disabled={counter.value <= 0}
|
||||
disabled={counter.value <= 0 || !!counter.archived_at}
|
||||
aria-label="Decrement"
|
||||
className="w-11 h-11 flex items-center justify-center text-ctp-red hover:bg-ctp-red/20 active:bg-ctp-red/30 active:scale-95 transition-all disabled:opacity-25 disabled:pointer-events-none"
|
||||
>
|
||||
@@ -83,7 +84,8 @@ export default function CounterCard({ counter, onIncrement, onDecrement, onEdit,
|
||||
<button
|
||||
onClick={() => onIncrement(counter.id)}
|
||||
aria-label="Increment"
|
||||
className="w-11 h-11 flex items-center justify-center text-ctp-green hover:bg-ctp-green/20 active:bg-ctp-green/30 active:scale-95 transition-all"
|
||||
disabled={!!counter.archived_at}
|
||||
className="w-11 h-11 flex items-center justify-center text-ctp-green hover:bg-ctp-green/20 active:bg-ctp-green/30 active:scale-95 transition-all disabled:opacity-25 disabled:pointer-events-none"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
|
||||
@@ -21,9 +21,11 @@ interface Props {
|
||||
image_path: string | null;
|
||||
}) => void;
|
||||
onDelete?: (id: number) => void;
|
||||
onArchive?: (id: number) => void;
|
||||
onUnarchive?: (id: number) => void;
|
||||
}
|
||||
|
||||
export default function CounterModal({ open, initial, groups, onClose, onSave, onDelete }: Props) {
|
||||
export default function CounterModal({ open, initial, groups, onClose, onSave, onDelete, onArchive, onUnarchive }: Props) {
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
const deleteTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const [name, setName] = useState('');
|
||||
@@ -191,28 +193,48 @@ export default function CounterModal({ open, initial, groups, onClose, onSave, o
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between gap-3 pt-2">
|
||||
{/* Delete — only shown when editing an existing counter */}
|
||||
{initial && onDelete ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (confirmDelete) {
|
||||
if (deleteTimer.current) clearTimeout(deleteTimer.current);
|
||||
onDelete(initial.id);
|
||||
onClose();
|
||||
} else {
|
||||
setConfirmDelete(true);
|
||||
deleteTimer.current = setTimeout(() => setConfirmDelete(false), 3000);
|
||||
}
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded-lg font-medium transition-colors ${
|
||||
confirmDelete
|
||||
? 'bg-ctp-red hover:bg-ctp-maroon text-ctp-base'
|
||||
: 'text-ctp-red hover:bg-ctp-red/10 border border-ctp-red/30'
|
||||
}`}
|
||||
>
|
||||
{confirmDelete ? 'Confirm delete' : 'Delete counter'}
|
||||
</button>
|
||||
{initial ? (
|
||||
initial.archived_at ? (
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { onUnarchive?.(initial.id); onClose(); }}
|
||||
className="px-4 py-2 text-sm rounded-lg font-medium border border-ctp-green/40 text-ctp-green hover:bg-ctp-green/10 transition-colors"
|
||||
>
|
||||
Unarchive
|
||||
</button>
|
||||
{onDelete && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (confirmDelete) {
|
||||
if (deleteTimer.current) clearTimeout(deleteTimer.current);
|
||||
onDelete(initial.id);
|
||||
onClose();
|
||||
} else {
|
||||
setConfirmDelete(true);
|
||||
deleteTimer.current = setTimeout(() => setConfirmDelete(false), 3000);
|
||||
}
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded-lg font-medium transition-colors ${
|
||||
confirmDelete
|
||||
? 'bg-ctp-red hover:bg-ctp-maroon text-ctp-base'
|
||||
: 'text-ctp-red hover:bg-ctp-red/10 border border-ctp-red/30'
|
||||
}`}
|
||||
>
|
||||
{confirmDelete ? 'Confirm delete' : 'Delete'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { onArchive?.(initial.id); onClose(); }}
|
||||
className="px-4 py-2 text-sm rounded-lg font-medium border border-ctp-overlay1/40 text-ctp-subtext1 hover:bg-ctp-surface1 transition-colors"
|
||||
>
|
||||
Archive
|
||||
</button>
|
||||
)
|
||||
) : <span />}
|
||||
|
||||
<div className="flex gap-3">
|
||||
|
||||
Reference in New Issue
Block a user