Skip to content

Commit eea531e

Browse files
committed
fixed for eslint
1 parent 88e007c commit eea531e

5 files changed

Lines changed: 195 additions & 8 deletions

File tree

client/src/components/task_form.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { useState } from "react";
22

3+
import { TimeInput } from "@/components/time_input";
4+
35
interface Time {
46
id: number;
57
day: number;
@@ -31,6 +33,9 @@ interface TaskFormProps {
3133
export function TaskForm({ userId, onTaskCreated }: TaskFormProps) {
3234
const [taskName, setTaskName] = useState("");
3335
const [description, setDescription] = useState("");
36+
const [times, setTimes] = useState<Time[]>([]);
37+
//const [existingTopicIds, setExistingTopicIds] = useState<number[]>([]);
38+
//const [newTopics, setNewTopics] = useState<{ name: string; color_hex: string }[]>([]);
3439

3540
const handleSubmit = async (e: React.FormEvent) => {
3641
e.preventDefault();
@@ -45,6 +50,9 @@ export function TaskForm({ userId, onTaskCreated }: TaskFormProps) {
4550
description: description,
4651
completed: false,
4752
user_id: userId,
53+
times: times,
54+
//existing_topic_ids: existingTopicIds,
55+
//new_topics: newTopics,
4856
}),
4957
});
5058

@@ -80,6 +88,7 @@ export function TaskForm({ userId, onTaskCreated }: TaskFormProps) {
8088
placeholder="Description"
8189
className="h-32 w-full resize-none rounded border-2 bg-zinc-700 p-2 text-zinc-200"
8290
/>
91+
<TimeInput times={times} setTimes={setTimes} />
8392
<button
8493
type="submit"
8594
className="rounded border-2 border-zinc-200 bg-blue-600 px-4 py-2 text-zinc-200 hover:bg-blue-700"
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
interface Time {
2+
id: number;
3+
day: number;
4+
start_time: string;
5+
end_time: string;
6+
repeating: boolean;
7+
}
8+
9+
interface TimeInputProps {
10+
times: Time[];
11+
setTimes: (times: Time[]) => void;
12+
}
13+
14+
const daysOfWeek = [
15+
{ label: "Mon", value: 1 },
16+
{ label: "Tue", value: 2 },
17+
{ label: "Wed", value: 3 },
18+
{ label: "Thu", value: 4 },
19+
{ label: "Fri", value: 5 },
20+
{ label: "Sat", value: 6 },
21+
{ label: "Sun", value: 7 },
22+
];
23+
24+
export function TimeInput({ times, setTimes }: TimeInputProps) {
25+
return (
26+
<div>
27+
{times.map((time, index) => (
28+
<div key={index}>
29+
<select
30+
value={time.day}
31+
onChange={(e) => {
32+
const newTimes = [...times];
33+
newTimes[index].day = parseInt(e.target.value);
34+
setTimes(newTimes);
35+
}}
36+
>
37+
{daysOfWeek.map((day) => (
38+
<option key={day.value} value={day.value}>
39+
{day.label}
40+
</option>
41+
))}
42+
</select>
43+
<input
44+
type="time"
45+
value={time.start_time}
46+
onChange={(e) => {
47+
const newTimes = [...times];
48+
newTimes[index].start_time = e.target.value;
49+
setTimes(newTimes);
50+
}}
51+
/>
52+
<input
53+
type="time"
54+
value={time.end_time}
55+
onChange={(e) => {
56+
const newTimes = [...times];
57+
newTimes[index].end_time = e.target.value;
58+
setTimes(newTimes);
59+
}}
60+
/>
61+
<input
62+
type="checkbox"
63+
checked={time.repeating}
64+
onChange={(e) => {
65+
const newTimes = [...times];
66+
newTimes[index].repeating = e.target.checked;
67+
setTimes(newTimes);
68+
}}
69+
/>
70+
<button
71+
type="button"
72+
onClick={() => setTimes(times.filter((_, i) => i !== index))}
73+
>
74+
Remove
75+
</button>
76+
</div>
77+
))}
78+
<button
79+
type="button"
80+
onClick={() =>
81+
setTimes([
82+
...times,
83+
{ id: 0, day: 1, start_time: "", end_time: "", repeating: false },
84+
])
85+
}
86+
>
87+
Add Time
88+
</button>
89+
</div>
90+
);
91+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
interface Topic {
2+
id: number;
3+
name: string;
4+
color_hex: number;
5+
}
6+
7+
type TopicSelection =
8+
| { type: "existing"; id: number }
9+
| { type: "new"; name: string; color_hex: number };
10+
11+
interface TopicInputProps {
12+
availableTopics: Topic[];
13+
topics: TopicSelection[];
14+
setTopics: React.Dispatch<React.SetStateAction<TopicSelection[]>>;
15+
}
16+
17+
export function TopicInput({
18+
availableTopics,
19+
topics,
20+
setTopics,
21+
}: TopicInputProps) {
22+
return (
23+
<div className="mb-4">
24+
<select
25+
className="w-full rounded border-2 bg-zinc-700 p-2 text-zinc-200"
26+
onChange={(e) => {
27+
const id = Number(e.target.value);
28+
if (!id) return;
29+
if (!topics.some((t) => t.type === "existing" && t.id === id)) {
30+
setTopics([...topics, { type: "existing", id }]);
31+
}
32+
e.target.value = "";
33+
}}
34+
>
35+
<option value="">Select Existing Topic</option>
36+
{availableTopics.map((topic) => (
37+
<option key={topic.id} value={topic.id}>
38+
{topic.name}
39+
</option>
40+
))}
41+
</select>
42+
</div>
43+
);
44+
}

server/task_planner/serializers.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,71 @@
11
from rest_framework import serializers
2+
from django.db import transaction
23
from .models import Task, Topic, Time
34

45

5-
class TopicSerializer(serializers.ModelSerializer):
6+
class TopicReadSerializer(serializers.ModelSerializer):
67
class Meta:
78
model = Topic
89
fields = "__all__"
910

1011

11-
class TimeSerializer(serializers.ModelSerializer):
12+
class TimeReadSerializer(serializers.ModelSerializer):
1213
class Meta:
1314
model = Time
1415
fields = "__all__"
1516

1617

1718
class TaskReadSerializer(serializers.ModelSerializer):
18-
topics = TopicSerializer(many=True, read_only=True)
19-
times = TimeSerializer(many=True, read_only=True)
19+
topics = TopicReadSerializer(many=True, read_only=True)
20+
times = TimeReadSerializer(many=True, read_only=True)
2021

2122
class Meta:
2223
model = Task
2324
fields = "__all__"
2425

26+
class TopicWriteSerializer(serializers.ModelSerializer):
27+
class Meta:
28+
model = Topic
29+
fields = ["name", "color_hex"]
30+
31+
class TimeWriteSerializer(serializers.ModelSerializer):
32+
class Meta:
33+
model = Time
34+
fields = ["day", "start_time", "end_time", "repeating"]
35+
2536
class TaskWriteSerializer(serializers.ModelSerializer):
37+
existing_topic_ids = serializers.PrimaryKeyRelatedField(
38+
many=True, queryset=Topic.objects.all(), write_only=True, required=False
39+
)
40+
new_topics = TopicWriteSerializer(many=True, write_only=True, required=False)
41+
times = TimeWriteSerializer(many=True, required=False)
42+
2643
class Meta:
2744
model = Task
28-
fields = ["name", "description", "completed"]
45+
fields = ["name", "description", "completed", "existing_topic_ids", "new_topics", "times"]
46+
47+
@transaction.atomic
48+
def create(self, validated_data):
49+
existing_topics = validated_data.pop("existing_topic_ids", [])
50+
new_topics_data = validated_data.pop("new_topics", [])
51+
times_data = validated_data.pop("times", [])
52+
53+
task = Task.objects.create(**validated_data)
54+
user = task.user
55+
56+
if not user:
57+
raise serializers.ValidationError("Task user is required to create topics.")
58+
59+
for topic in existing_topics:
60+
task.topics.add(topic)
61+
62+
for topic_data in new_topics_data:
63+
topic = Topic.objects.create(**topic_data, user=task.user)
64+
task.topics.add(topic)
65+
66+
Time.objects.bulk_create([
67+
Time(task=task, **time_data)
68+
for time_data in times_data
69+
])
70+
71+
return task

server/task_planner/views.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@
88
#from rest_framework.permissions import IsAuthenticated
99

1010
from .models import Task, Topic, Time
11-
from .serializers import TaskReadSerializer, TaskWriteSerializer, TopicSerializer, TimeSerializer
11+
from .serializers import TaskReadSerializer, TaskWriteSerializer, TopicReadSerializer, TimeReadSerializer
1212

1313

1414
# Create your views here.
1515

1616
class TopicList(APIView):
1717
def get(self, request):
1818
topics = Topic.objects.all()
19-
serializer = TopicSerializer(topics, many=True)
19+
serializer = TopicReadSerializer(topics, many=True)
2020
return Response(serializer.data)
2121

2222

2323
class TimeList(APIView):
2424
def get(self, request):
2525
times = Time.objects.all()
26-
serializer = TimeSerializer(times, many=True)
26+
serializer = TimeReadSerializer(times, many=True)
2727
return Response(serializer.data)
2828

2929
class TaskViewSet(ModelViewSet):

0 commit comments

Comments
 (0)