Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ database.plugin(leanIdPlugin);

/* setup the platform and global middleware */
const platform = new ExpressPlatform();
platform.use(cors({ origin: [appUrl], credentials: true }));
platform.use(cors({ origin: [appUrl, ], credentials: true }));
platform.set("trust proxy", 4);

platform.use(session({
Expand Down
42 changes: 11 additions & 31 deletions packages/api/src/task/subtask.entity.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
import { Entity, Model, Prop } from "@/_lib/mongoose";
import mongoose from "mongoose";

@Entity()
export class SubTask extends Model {

id: string;

@Prop({ type: String, required: true })
export interface SubTask {
id?: string;
title: string;

@Prop({ type: String, default: "" })
description: string;

/** this should be changed to a Date object, but current filtering logic is using regex on a string */
@Prop({ type: String, default: () => new Date().toString() })
description?: string;
/** currently stored as string for legacy reasons */
date: string;

@Prop({ type: mongoose.Schema.Types.Mixed, default: false })
done: boolean | string[];

@Prop({ type: String, default: "" })
repeater: string;

@Prop({ type: String, default: "" })
reminder: string;

@Prop({ type: String, default: "" })
type: string;

/** (git blame Hiro) - figure out what this actually does */
@Prop({ type: Boolean, default: false })
accordion: boolean;

repeater?: string;
reminder?: string;
type?: string;
accordion?: boolean;
priority?: number;
tags?: string[];
subtasks?: SubTask[];
}
5 changes: 2 additions & 3 deletions packages/api/src/task/task.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Entity, Model, Prop } from "@/_lib/mongoose";
import mongoose from "mongoose";
import { SubTask } from "./subtask.entity";
import { User } from "../user/user.entity";

@Entity()
Expand Down Expand Up @@ -37,8 +36,8 @@ export class Task extends Model {
@Prop({ type: Number, default: 0 })
priority: number;

@Prop({ type: [SubTask], default: [] })
subtasks: SubTask[];
@Prop({ type: String, default: "" })
group: string;

@Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }], default: [] })
users: (User | string)[];
Expand Down
21 changes: 11 additions & 10 deletions packages/api/src/task/task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ export class TaskService {

async addTask(data: Partial<Task>): Promise<Task> {
const tags = this.normalizeTags(data.tags);
return Task.create({ ...data, ...(tags ? { tags } : {}) });
return Task.create({
...data,
...(tags ? { tags } : {}),
});
}

async addTasks(data: Partial<Task>[]): Promise<Task[]> {
Expand All @@ -38,9 +41,13 @@ export class TaskService {
async updateTask(id: string, data: Partial<Task> | UpdateQuery<Task>): Promise<Task | null> {
const tags = this.normalizeTags((data as Partial<Task>)?.tags);

const update: Partial<Task> | UpdateQuery<Task> = tags
? { ...(data as Partial<Task>), tags }
: data;
const update: Partial<Task> | UpdateQuery<Task> = {
...(data as Partial<Task>),
...(tags ? { tags } : {}),
};

// Explicitly drop any subtasks payloads
(update as any).subtasks = undefined;

return Task.findByIdAndUpdate(id, update).lean<Task>().exec();
}
Expand All @@ -54,7 +61,6 @@ export class TaskService {
}

return Task.find(query)
.populate("subtasks")
.populate({ path: "users", select: "first last email id" })
.lean<Task[]>()
.exec();
Expand Down Expand Up @@ -91,7 +97,6 @@ export class TaskService {
const todayFormat = this.getTaskDateFormat(new Date());

return Task.find({ users: userId, date: { $regex: todayFormat }, done: false })
.populate("subtasks")
.populate({ path: "users", select: "first last email id" })
.lean<Task[]>()
.exec();
Expand All @@ -104,7 +109,6 @@ export class TaskService {
const tomorrowFormat = this.getTaskDateFormat(today);

return Task.find({ users: userId, date: { $regex: tomorrowFormat }, done: false })
.populate("subtasks")
.populate({ path: "users", select: "first last email id" })
.lean<Task[]>()
.exec();
Expand All @@ -115,7 +119,6 @@ export class TaskService {
const format = this.getTaskDateWeekFormat(today);

return Task.find({ users: userId, date: { $regex: format }, done: false })
.populate("subtasks")
.populate({ path: "users", select: "first last email id" })
.lean<Task[]>()
.exec();
Expand All @@ -126,7 +129,6 @@ export class TaskService {
today.setHours(0, 0, 0, 0);

const tasks = await Task.find({ users: userId, done: false })
.populate("subtasks")
.populate({ path: "users", select: "first last email id" })
.lean<Task[]>()
.exec();
Expand All @@ -142,7 +144,6 @@ export class TaskService {

async getTasksIncomplete(userId: string): Promise<Task[]> {
return Task.find({ users: userId, done: false })
.populate("subtasks")
.populate({ path: "users", select: "first last email id" })
.sort({ priority: -1 })
.lean<Task[]>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,7 @@ export default function TaskContainer({
})
.filter(Boolean)
: [];
const subtaskTags = Array.isArray(task.subtasks)
? task.subtasks.flatMap((subtask) =>
Array.isArray(subtask.tags)
? subtask.tags
.map((tag) => {
if (typeof tag === "string") return tag.toLowerCase();
if (tag && typeof (tag as any).title === "string") return (tag as any).title.toLowerCase();
return "";
})
.filter(Boolean)
: []
)
: [];

const combined = [...ownTags, ...subtaskTags];
return activeTags.every((tag) => combined.includes(tag));
return activeTags.every((tag) => ownTags.includes(tag));
};

if (activeTags.length > 0) {
Expand Down
106 changes: 7 additions & 99 deletions packages/app/src/components/task/TaskItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Task, useDeleteTask, useUpdateTask } from "@/hooks/tasks";
import { Task, useUpdateTask } from "@/hooks/tasks";
import { matchDate } from "@/utils/date";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
Expand All @@ -8,18 +8,19 @@ import TaskItemTitle from "./TaskItemTitle";
import TaskItemDate from "./TaskItemDate";
import { isTaskDone } from "@/utils/data";
import { useApp } from "@/hooks/app";
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/20/solid";

interface TaskItemParams {
skeleton: boolean;
item?: Task;
setIsInspecting?: (open: boolean) => void;
taskFilter?: string;
selectionMode?: boolean;
isSelected?: boolean;
onToggleSelect?: (id: string) => void;
isAnimating?: boolean;
}

export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFilter, selectionMode = false, isSelected = false, onToggleSelect, isAnimating = false }: TaskItemParams) {

export function TaskItem({ skeleton, item, setIsInspecting, taskFilter, selectionMode = false, isSelected = false, onToggleSelect, isAnimating = false }: TaskItemParams) {
if (skeleton) {
return (
<div className="w-full flex flex-col gap-2">
Expand Down Expand Up @@ -53,17 +54,12 @@ export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFi

const navigate = useNavigate();

const { mutate: deleteTask } = useDeleteTask();
const { mutate: updateTask } = useUpdateTask();

const [appData, setAppData] = useApp();


const [isDeleting, setIsDeleting] = useState(false);
const [isManaging, setIsManaging] = useState(false);
const [isCompleting, setIsCompleting] = useState(false);

const [isAccordion, setAccordion] = useState(item.accordion || false);
const tags = Array.isArray(item.tags)
? item.tags
.map((tag) => {
Expand Down Expand Up @@ -102,38 +98,9 @@ export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFi
if (!foundDate) newDone.push(rawDate);
else newDone.splice(newDone.indexOf(rawDate), 1);

if (type == "subtask") {
const newSubs = [...parent.subtasks];
for (let i = 0; i < newSubs.length; i++) {
if (newSubs[i].id == item.id) newSubs[i] = { ...item, done: newDone };
}

newData = {
...parent,
subtasks: newSubs,
};

updateTask({ id: parent.id, data: newData });
} else {
updateTask({ id: item.id, data: { ...item, done: newDone } });
}
updateTask({ id: item.id, data: { ...item, done: newDone } });
} else {
if (type == "subtask") {
const newSubs = [...parent.subtasks];
for (let i = 0; i < newSubs.length; i++) {
if (newSubs[i].id == item.id)
newSubs[i] = { ...item, done: !item.done };
}

newData = {
...parent,
subtasks: newSubs,
};

updateTask({ id: parent.id, data: newData });
} else {
updateTask({ id: item.id, data: { ...item, done: !item.done } });
}
updateTask({ id: item.id, data: { ...item, done: !item.done } });
}

setIsManaging(false);
Expand All @@ -149,11 +116,6 @@ export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFi
return;
}

if (type == "subtask") {
handleInteractiveSubtask(e);
return;
}

e.stopPropagation();

setAppData({
Expand All @@ -164,18 +126,6 @@ export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFi
setIsInspecting(true);
};

const handleInteractiveSubtask = (e: any) => {
e.stopPropagation();

setAppData({
...appData,
activeParent: parent,
activeTask: item,
});

setIsInspecting(true);
};

const selectionClass = selectionMode
? isSelected
? "ring-2 ring-accent-blue/40"
Expand Down Expand Up @@ -220,28 +170,6 @@ export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFi
<div className="w-full">
<div className="w-full flex flex-row items-center justify-between">
<TaskItemTitle text={item.title} />
{item.type == "group" && item.subtasks?.length > 0 && (
<div>
<div
onClick={(e) => {
e.stopPropagation();
const newValue = !isAccordion;

setAccordion(newValue);
updateTask({
id: item.id,
data: {
...item,
accordion: newValue,
},
});
}}
>
{!isAccordion && <ChevronDownIcon width="32" />}
{isAccordion && <ChevronUpIcon width="32" />}
</div>
</div>
)}
</div>
<div className="w-fit flex flex-row flex-end items-center justify-start px-2">
<div className="w-full h-full flex items-center justify-evenly">
Expand All @@ -263,26 +191,6 @@ export function TaskItem({ skeleton, item, setIsInspecting, type, parent, taskFi
</div>
</div>
</TaskItemShell>
<div className="w-full flex justify-end">
<div className="w-full pl-10 flex flex-col justify-end gap-1">
{item.type == "group" &&
!isAccordion &&
item.subtasks?.map((subtask: Task, key: number) => (
<div
className="w-full flex flex-row justify-center items-center"
key={key}
>
<TaskItem
taskFilter={taskFilter}
type="subtask"
parent={item}
item={subtask}
setIsInspecting={setIsInspecting}
/>
</div>
))}
</div>
</div>
</div>
);
}
7 changes: 1 addition & 6 deletions packages/app/src/components/tasks/TagFilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@ export default function TagFilterBar({ tasks }: TagFilterBarProps) {
if (!pending) return;

const tags = Array.isArray(task?.tags) ? task.tags : [];
const subtaskTags = Array.isArray(task?.subtasks)
? task.subtasks.flatMap((subtask) =>
Array.isArray(subtask.tags) ? subtask.tags : []
)
: [];

[...tags, ...subtaskTags].forEach((tag) => {
tags.forEach((tag) => {
const normalized = typeof tag === "string"
? tag.toLowerCase()
: tag && typeof (tag as any).title === "string"
Expand Down
Loading