Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ea3d0b2
Merge branch 'fix-schedule-page-bugs' into tasks-page-frontend-upgrade
Archer-Key Jan 7, 2026
708a8d5
changed styling of task page, task_list, and task_item (view mode onl…
Archer-Key Jan 7, 2026
797655c
removed day prop from TimeTag and created new DayTag component
Archer-Key Jan 7, 2026
b0bec66
changed API endpoing on schedule page from /task to /tasks to work wi…
Archer-Key Jan 7, 2026
93ea212
changed TaskItem title and description's styling and TimeInput' styli…
Archer-Key Jan 8, 2026
cd8d665
changed styling of TopicInput component to match other components
Archer-Key Jan 8, 2026
0501411
changed styling of TaskForm to match other components
Archer-Key Jan 8, 2026
5c3b0c0
added AddTask section to Tasks page
Archer-Key Jan 8, 2026
dd1196c
added a view-tasks-section div to match the add-task-section on Tasks…
Archer-Key Jan 8, 2026
9b89892
added placeholder styling for task_form to make text-color align with…
Archer-Key Jan 8, 2026
a34b930
removed view-tasks-section and add-task-section divs for better scali…
Archer-Key Jan 8, 2026
bee6fe9
removed justify-between from topic tags container on TimetableTaskCon…
Archer-Key Jan 8, 2026
cfa4379
added shadows to task pages main components, removed some old hover e…
Archer-Key Jan 8, 2026
2a74b20
merged issue-7-Allow_CRUD_Operations_on_Tasks's latest change to add …
Archer-Key Jan 9, 2026
d8a3423
installed react-icons package in client, replaced icon placeholders w…
Archer-Key Jan 9, 2026
8610a11
moved edit and delete buttons to top right of TaskItem for better UI/UX
Archer-Key Jan 9, 2026
bc8bcd9
changed time tags on task item to display in a row for better UI, add…
Archer-Key Jan 9, 2026
044444c
removed x gap from task times container as horizontal padding on the …
Archer-Key Jan 9, 2026
b518f1c
removed border from task page and overflow cutting page off at view h…
Archer-Key Jan 9, 2026
b1f1f4a
added a toggle button to toggle the visibility of the add tasks form
Archer-Key Jan 9, 2026
6f39058
increased minimum size of content containers on tasks and schedule pa…
Archer-Key Jan 9, 2026
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
10 changes: 10 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"next": "15.4.7",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-icons": "^5.5.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7"
},
Expand Down
31 changes: 18 additions & 13 deletions client/src/components/task_form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,34 +93,39 @@ export function TaskForm({ userId, onTaskCreated }: TaskFormProps) {
return (
<form
onSubmit={handleSubmit}
className="mx-auto h-[79vh] w-full max-w-md space-y-4 overflow-y-auto rounded-xl bg-zinc-700 p-4"
className="task-form flex h-full w-full flex-col items-center justify-between gap-2 rounded-lg bg-slate-400 p-4 text-slate-200"
>
<input
className="title-input w-full rounded-lg bg-slate-400 px-3 py-1 text-3xl font-bold text-slate-100 brightness-90 placeholder:text-slate-300 hover:brightness-110"
type="text"
value={taskName}
onChange={(e) => setTaskName(e.target.value)}
placeholder="Task Name"
className="w-full rounded border-2 bg-zinc-700 p-2 text-zinc-200"
placeholder="Task name"
required
/>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Description"
className="h-32 w-full resize-none rounded border-2 bg-zinc-700 p-2 text-zinc-200"
/>
<TimeInput times={times} setTimes={setTimes} />
<div className="description-wrapper flex w-full flex-col items-center">
<h1 className="description-input-title text-xl hover:brightness-110">
Description
</h1>
<textarea
className="description-input w-full rounded-lg bg-slate-400 p-2 brightness-90 placeholder:text-slate-300 hover:brightness-110"
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={7}
placeholder="Add description here..."
/>
</div>
<TopicInput
availableTopics={availableTopics}
topics={topics}
setTopics={setTopics}
/>

<TimeInput times={times} setTimes={setTimes} />
<button
className="w-fit rounded-lg border border-slate-300 bg-slate-400 px-3 py-1 text-xl brightness-110 hover:brightness-125"
type="submit"
className="rounded border-2 border-zinc-200 bg-blue-600 px-4 py-2 text-zinc-200 hover:bg-blue-700"
>
Add Task
Save
</button>
</form>
);
Expand Down
159 changes: 84 additions & 75 deletions client/src/components/task_item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { useState } from "react";
import { FaRegEdit } from "react-icons/fa";
import { FaRegTrashCan } from "react-icons/fa6";

import { TimeInput } from "@/components/time_input";
import TimeTag, { DayTag } from "@/components/time_tag";
import { TopicInput } from "@/components/topic_input";
import { TopicTagAlt } from "@/components/topic_tag";

interface Time {
id: number;
Expand Down Expand Up @@ -122,52 +126,61 @@ export function TaskItem({
/* Item Display */
}
return (
<div className="m-1 flex w-96 flex-col rounded-md border-2 border-zinc-200 bg-zinc-700 p-2">
<div className="flex items-center justify-between">
<div className="task flex h-fit w-full max-w-[48rem] flex-col gap-3 rounded-lg bg-slate-400 p-5 text-slate-200 shadow-xl">
<div className="task-title-container flex w-full flex-row items-center justify-start gap-2 text-3xl font-bold text-slate-100 hover:text-slate-100">
{/* Task Name and Completion */}
<div className="flex items-center space-x-2">
<input
className="task-completion mr-3 accent-slate-300"
type="checkbox"
checked={item.completed}
onChange={() => onToggle?.(item.id)}
/>
{isEditing ? (
<input
type="checkbox"
checked={item.completed}
onChange={() => onToggle?.(item.id)}
className="w-xl h-xl accent-zinc-600"
className="task-title-edit w-full rounded-lg bg-slate-400 px-3 py-1 brightness-90 hover:brightness-110"
value={draftName}
onChange={(e) => setDraftName(e.target.value)}
/>
{isEditing ? (
<input
value={draftName}
onChange={(e) => setDraftName(e.target.value)}
className="rounded border-2 bg-zinc-600 p-1 text-zinc-200"
/>
) : (
) : (
<>
<span
className={
item.completed ? "text-zinc-400 line-through" : "text-zinc-300"
"task-title w-full" + (item.completed ? " line-through" : "")
}
>
{item.name}
</span>
)}
</div>
<button className="hover:brightness-110" onClick={startEdit}>
<FaRegEdit className="h-5 w-5" />
</button>
<button onClick={() => onDelete(item.id)}>
<FaRegTrashCan className="h-5 w-5 hover:text-red-600" />
</button>
</>
)}
</div>

{/* Task Times */}
<div className="flex flex-col items-end text-sm text-zinc-300">
{isEditing ? (
<TimeInput times={draftTimes} setTimes={setDraftTimes} />
) : item.times?.length > 0 ? (
item.times.map((t) => (
<span key={t.id}>
{formatDay(t.day)} {t.start_time.slice(0, 5)} -{" "}
{t.end_time.slice(0, 5)}
</span>
))
) : (
"No time set"
)}
</div>
{/* Task Times */}
<div className="task-times-container flex flex-row flex-wrap items-start justify-start gap-y-1">
{isEditing ? (
<TimeInput times={draftTimes} setTimes={setDraftTimes} />
) : item.times?.length > 0 ? (
item.times.map((time) => (
<div
key={time.id}
className="day-time-tags flex w-fit flex-row gap-3 rounded-full bg-slate-400 px-3 py-1 hover:brightness-110"
>
<DayTag day={formatDay(time.day)} />
<TimeTag start_time={time.start_time} end_time={time.end_time} />
</div>
))
) : (
"No time set"
)}
</div>

{/* Task Topics */}
<div className="flex flex-wrap gap-1 text-sm text-zinc-300">
<div className="task-topic-tags flex flex-row flex-wrap gap-1 text-slate-200">
{isEditing ? (
<TopicInput
availableTopics={availableTopics}
Expand All @@ -176,73 +189,69 @@ export function TaskItem({
/>
) : item.topics.length > 0 ? (
item.topics.map((topic) => (
<span
<TopicTagAlt
key={topic.id}
className="flex items-center gap-1 rounded-lg border-2 border-zinc-500 px-2 py-0.5 text-zinc-100"
>
<span
className="h-2 w-2 rounded-full"
style={{
backgroundColor: `#${topic.color_hex
.toString(16)
.padStart(6, "0")}`,
}}
/>
{topic.name}
</span>
name={topic.name}
color_hex={topic.color_hex}
/>
))
) : (
"No topics"
)}
</div>

{/* Task Description */}
<div>
<div
className="task-description overflow-auto text-justify text-slate-200"
style={!isEditing ? { maxHeight: "12rem", scrollbarWidth: "thin" } : {}}
>
{isEditing ? (
<textarea
value={draftDescription}
onChange={(e) => setDraftDescription(e.target.value)}
className="mt-2 w-full rounded border-2 bg-zinc-600 p-1 text-zinc-200"
/>
) : item.description ? (
<span className="mt-2 block text-zinc-300">{item.description}</span>
<div className="task-description-input-container flex flex-col items-center gap-2">
<h1 className="description-input-title text-xl hover:brightness-110">
Description
</h1>
<textarea
className="w-full rounded-lg bg-slate-400 p-1 brightness-90 hover:brightness-110"
value={draftDescription}
rows={7}
onChange={(e) => setDraftDescription(e.target.value)}
/>
</div>
) : (
<span className="mt-2 block italic text-zinc-500">
No description.
<span className="block hover:brightness-110">
{item.description ? item.description : "No Description"}
</span>
)}
</div>

{/* Edit Button */}
<div className="mt-2 flex gap-2">

<div className="task-edit flex gap-2">
{isEditing ? (
<>
<button onClick={saveEdit} disabled={saving}>
<div className="flex w-full flex-row justify-center text-lg">
<button
className="rounded-full bg-slate-400 px-3 py-1 hover:brightness-110"
onClick={saveEdit}
disabled={saving}
>
Save
</button>
<button onClick={cancelEdit}>Cancel</button>
</>
<button
className="rounded-full bg-slate-400 px-3 py-1 hover:brightness-110"
onClick={cancelEdit}
>
Cancel
</button>
</div>
) : (
<button onClick={startEdit}>Edit</button>
)}
</div>

{/* Delete Button */}
<div>
{!isEditing && (
<button
onClick={() => onDelete(item.id)}
className="mt-2 text-red-500"
>
Delete Task
</button>
<></>
)}
</div>
</div>
);
}

function formatDay(day: number): string {
export function formatDay(day: number): string {
const days = [
"Monday",
"Tuesday",
Expand Down
30 changes: 14 additions & 16 deletions client/src/components/task_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,23 @@ export function TaskList({
if (items.length === 0) {
return (
<div>
<p className="text-center text-zinc-300">No tasks available.</p>
<p className="text-center text-slate-300">No tasks available.</p>
</div>
);
}
return (
<div className="mx-auto h-[79vh] w-full max-w-md overflow-y-auto p-2">
<ul className="space-y-2">
{items.map((item) => (
<li key={item.id}>
<TaskItem
item={item}
onToggle={onToggleTask}
onUpdate={onUpdate}
onDelete={onDelete}
availableTopics={availableTopics}
/>
</li>
))}
</ul>
</div>
<ul className="task-list h-fit space-y-3">
{items.map((item) => (
<li key={item.id}>
<TaskItem
item={item}
onToggle={onToggleTask}
onUpdate={onUpdate}
onDelete={onDelete}
availableTopics={availableTopics}
/>
</li>
))}
</ul>
);
}
Loading
Loading