fixed due today and made it due within 12 hrs either way. Also added 'complete until' language to recurring task status update dropdown
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import { type Component, createMemo, For, Show } from "solid-js";
|
import { type Component, createMemo, For, Show } from "solid-js";
|
||||||
import { type Task, calculateUrgencyFromDate, setActiveTaskId, store, copyTask, updateTask, currentTaskContext } from "@/store";
|
import { type Task, calculateUrgencyFromDate, setActiveTaskId, store, copyTask, updateTask, currentTaskContext, now } from "@/store";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Clock, ArrowUpCircle, Copy, Users2 } from "lucide-solid";
|
import { Clock, ArrowUpCircle, Copy, Users2 } from "lucide-solid";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { useTheme } from "./ThemeProvider";
|
import { useTheme } from "./ThemeProvider";
|
||||||
import { getThemeAdjustedColor } from "@/lib/colors";
|
import { getThemeAdjustedColor } from "@/lib/colors";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select";
|
import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select";
|
||||||
import { STATUS_OPTIONS } from "@/lib/constants";
|
import { getStatusOptionsForTask } from "@/lib/constants";
|
||||||
import { StatusCircle } from "./StatusCircle";
|
import { StatusCircle } from "./StatusCircle";
|
||||||
|
|
||||||
export const TaskCard: Component<{ task: Task }> = (props) => {
|
export const TaskCard: Component<{ task: Task }> = (props) => {
|
||||||
@@ -40,17 +40,20 @@ export const TaskCard: Component<{ task: Task }> = (props) => {
|
|||||||
return tags;
|
return tags;
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDueToday = createMemo(() => {
|
const isDueWithin12Hours = createMemo(() => {
|
||||||
if (!props.task.dueDate) return false;
|
if (!props.task.dueDate) return false;
|
||||||
try {
|
try {
|
||||||
const todayStr = new Date().toLocaleDateString('en-CA');
|
const dueMs = new Date(props.task.dueDate).getTime();
|
||||||
const dueStr = new Date(props.task.dueDate).toLocaleDateString('en-CA');
|
const diffMs = dueMs - now();
|
||||||
return todayStr === dueStr;
|
const twelveHoursMs = 12 * 60 * 60 * 1000;
|
||||||
|
return Math.abs(diffMs) <= twelveHoursMs;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const statusOptions = createMemo(() => getStatusOptionsForTask(props.task.recurrence));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={cn(
|
class={cn(
|
||||||
@@ -60,7 +63,7 @@ export const TaskCard: Component<{ task: Task }> = (props) => {
|
|||||||
onClick={() => setActiveTaskId(props.task.id)}
|
onClick={() => setActiveTaskId(props.task.id)}
|
||||||
>
|
>
|
||||||
{/* Today indicator */}
|
{/* Today indicator */}
|
||||||
<Show when={isDueToday() && !props.task.completed}>
|
<Show when={isDueWithin12Hours() && !props.task.completed}>
|
||||||
<div class="absolute left-0 top-3 bottom-3 w-1 bg-primary rounded-r-md" />
|
<div class="absolute left-0 top-3 bottom-3 w-1 bg-primary rounded-r-md" />
|
||||||
</Show>
|
</Show>
|
||||||
{/* Status Dropdown */}
|
{/* Status Dropdown */}
|
||||||
@@ -74,7 +77,7 @@ export const TaskCard: Component<{ task: Task }> = (props) => {
|
|||||||
if (!isNaN(s)) updateTask(props.task.id, { status: s });
|
if (!isNaN(s)) updateTask(props.task.id, { status: s });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
options={STATUS_OPTIONS}
|
options={statusOptions()}
|
||||||
optionValue="value"
|
optionValue="value"
|
||||||
optionTextValue="label"
|
optionTextValue="label"
|
||||||
placeholder="Status"
|
placeholder="Status"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { calculateDateFromUrgency, calculateUrgencyFromDate } from "@/store";
|
|||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { TagPicker } from "./TagPicker";
|
import { TagPicker } from "./TagPicker";
|
||||||
import { Badge } from "./ui/badge";
|
import { Badge } from "./ui/badge";
|
||||||
import { PRIORITY_OPTIONS, URGENCY_OPTIONS, SIZE_OPTIONS, STATUS_OPTIONS } from "@/lib/constants";
|
import { PRIORITY_OPTIONS, URGENCY_OPTIONS, SIZE_OPTIONS, getStatusOptionsForTask } from "@/lib/constants";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { toast } from "solid-sonner";
|
import { toast } from "solid-sonner";
|
||||||
@@ -136,6 +136,8 @@ export const TaskDetail: Component<TaskDetailProps> = (props) => {
|
|||||||
return tags;
|
return tags;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const statusOptions = createMemo(() => getStatusOptionsForTask(props.task.recurrence));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sheet open={props.isOpen} onOpenChange={(open) => {
|
<Sheet open={props.isOpen} onOpenChange={(open) => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
@@ -164,7 +166,7 @@ export const TaskDetail: Component<TaskDetailProps> = (props) => {
|
|||||||
<Select<any>
|
<Select<any>
|
||||||
value={(props.task.status ?? 0).toString()}
|
value={(props.task.status ?? 0).toString()}
|
||||||
onChange={(val: string | null) => val && updateStatus(val)}
|
onChange={(val: string | null) => val && updateStatus(val)}
|
||||||
options={STATUS_OPTIONS}
|
options={statusOptions()}
|
||||||
optionValue="value"
|
optionValue="value"
|
||||||
optionTextValue="label"
|
optionTextValue="label"
|
||||||
placeholder="Status"
|
placeholder="Status"
|
||||||
|
|||||||
@@ -68,3 +68,44 @@ export const STATUS_OPTIONS = [
|
|||||||
{ value: "1", label: "1" },
|
{ value: "1", label: "1" },
|
||||||
{ value: "0", label: "0 - Not Yet Started" }
|
{ value: "0", label: "0 - Not Yet Started" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
|
||||||
|
type Recurrence = {
|
||||||
|
type: 'daily' | 'weekly' | 'monthly';
|
||||||
|
days?: number[];
|
||||||
|
dayOfMonth?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRecurrenceCompleteLabel = (recurrence?: Recurrence | null): string => {
|
||||||
|
if (!recurrence) return "10 - Complete";
|
||||||
|
if (recurrence.type === 'daily') return "10 - Complete until tomorrow";
|
||||||
|
if (recurrence.type === 'weekly') {
|
||||||
|
if (recurrence.days && recurrence.days.length > 0) {
|
||||||
|
const today = new Date().getDay();
|
||||||
|
const sorted = [...recurrence.days].sort((a, b) => {
|
||||||
|
const da = (a - today + 7) % 7 || 7;
|
||||||
|
const db = (b - today + 7) % 7 || 7;
|
||||||
|
return da - db;
|
||||||
|
});
|
||||||
|
return `10 - Complete until ${DAY_NAMES[sorted[0]]}`;
|
||||||
|
}
|
||||||
|
return "10 - Complete (weekly)";
|
||||||
|
}
|
||||||
|
if (recurrence.type === 'monthly') {
|
||||||
|
const dom = recurrence.dayOfMonth;
|
||||||
|
if (dom != null) {
|
||||||
|
const suffix = dom === 1 || dom === 21 || dom === 31 ? 'st'
|
||||||
|
: dom === 2 || dom === 22 ? 'nd'
|
||||||
|
: dom === 3 || dom === 23 ? 'rd' : 'th';
|
||||||
|
return `10 - Complete until the ${dom}${suffix}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "10 - Complete";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStatusOptionsForTask = (recurrence?: Recurrence | null) =>
|
||||||
|
STATUS_OPTIONS.map(opt =>
|
||||||
|
opt.value === "10" ? { ...opt, label: getRecurrenceCompleteLabel(recurrence) } : opt
|
||||||
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user