diff --git a/client/src/api/entries.ts b/client/src/api/entries.ts index d4237a7..053d3cb 100644 --- a/client/src/api/entries.ts +++ b/client/src/api/entries.ts @@ -1,7 +1,8 @@ import axios, { AxiosResponse } from "axios"; -import { BASE_URL, handleRequestError } from "~/utils"; -import { IEntry, Status } from "~/~/models/Entry"; +import { BASE_URL } from "~/utils/constants"; +import { handleRequestError } from "~/utils/handlers"; +import { IEntry, Status } from "~/utils/types"; type UpdateResponse = { message: string; diff --git a/client/src/api/tasks.ts b/client/src/api/tasks.ts index c8e76da..bd874a9 100644 --- a/client/src/api/tasks.ts +++ b/client/src/api/tasks.ts @@ -1,15 +1,13 @@ import axios, { AxiosResponse } from "axios"; -import mongoose from "mongoose"; -import { BASE_URL, handleRequestError } from "~/utils"; -import { ITask } from "~/~/models/Task"; +import { BASE_URL } from "~/utils/constants"; +import { handleRequestError } from "~/utils/handlers"; +import { ITask } from "~/utils/types"; type MessageResponse = { message: string; }; -type MongooseId = mongoose.Types.ObjectId; - // Get user's tasks export async function getUserTasks() { try { @@ -53,7 +51,7 @@ export async function createTask(title: string) { } // Update title -export async function updateTask(taskId: MongooseId, title: string) { +export async function updateTask(taskId: string, title: string) { try { const response: AxiosResponse = await axios.patch( `${BASE_URL}/tasks/${taskId}`, @@ -73,7 +71,7 @@ export async function updateTask(taskId: MongooseId, title: string) { } // Delete -export async function deleteTask(taskId: MongooseId) { +export async function deleteTask(taskId: string) { try { const response: AxiosResponse = await axios.delete( `${BASE_URL}/tasks/${taskId}`, diff --git a/client/src/api/users.ts b/client/src/api/users.ts index 5e29f7d..b3f8efc 100644 --- a/client/src/api/users.ts +++ b/client/src/api/users.ts @@ -1,8 +1,8 @@ import axios, { AxiosResponse } from "axios"; -import { BASE_URL, handleRequestError } from "~/utils"; -import { ITask } from "~/~/models/Task"; -import { IUser } from "~/~/models/User"; +import { BASE_URL } from "~/utils/constants"; +import { handleRequestError } from "~/utils/handlers"; +import { ITask, IUser } from "~/utils/types"; export interface IMonthData { month: number; diff --git a/client/src/components/CreateTaskForm.tsx b/client/src/components/CreateTaskForm.tsx index 0f55abf..b87a0d9 100644 --- a/client/src/components/CreateTaskForm.tsx +++ b/client/src/components/CreateTaskForm.tsx @@ -1,10 +1,8 @@ import { FormEvent, useState } from "react"; -import { Input } from "./ui/Input"; -import { Button } from "./ui/Button"; - +import { Input, Button } from "./ui"; import { createTask } from "~/api/tasks"; -import { ITask } from "~/~/models/Task"; +import { ITask } from "~/utils/types"; interface CreateTaskForm { handleOnCreate: (task: ITask) => void; diff --git a/client/src/components/Entry.tsx b/client/src/components/Entry.tsx index 1377a7c..64476d2 100644 --- a/client/src/components/Entry.tsx +++ b/client/src/components/Entry.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from "react"; import { useAppContext, useMonthContext } from "~/hooks"; -import { cn, statusColor } from "~/utils"; -import { IEntry } from "~/~/models/Entry"; +import { cn, statusColor } from "~/utils/handlers"; +import { type IEntry } from "~/utils/types"; interface EntryProps { entry: IEntry; diff --git a/client/src/components/MonthCard.tsx b/client/src/components/MonthCard.tsx index 70b4159..8fda3f0 100644 --- a/client/src/components/MonthCard.tsx +++ b/client/src/components/MonthCard.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from "react"; -import mongoose from "mongoose"; import { MonthCardDays } from "./MonthCardDays"; import { MonthCardHeader } from "./MonthCardHeader"; @@ -10,11 +9,12 @@ import { CreateTaskForm } from "./CreateTaskForm"; import { useAppContext, useEntries, useMonthRating } from "~/hooks"; import { IMonthData } from "~/api/users"; import { deleteTask } from "~/api/tasks"; -import { calculateStatusPercentage, filterDeletedRatings } from "~/utils"; -import { ITask } from "~/~/models/Task"; -import { Status } from "~/~/models/Entry"; -type MongooseId = mongoose.Types.ObjectId; +import { + calculateStatusPercentage, + filterDeletedRatings, +} from "~/utils/handlers"; +import { Status, type ITask } from "~/utils/types"; interface MonthCardProps { year: number; @@ -64,7 +64,7 @@ export function MonthCard({ year, monthData }: MonthCardProps) { // Delete async function handleDeleteTask( - taskId: MongooseId, + taskId: string, deletedTaskRatings: Status[], ) { const updatedTasks = monthTasks.filter((task) => task._id !== taskId); diff --git a/client/src/components/MonthCardDays.tsx b/client/src/components/MonthCardDays.tsx index 54550f6..747f08e 100644 --- a/client/src/components/MonthCardDays.tsx +++ b/client/src/components/MonthCardDays.tsx @@ -1,5 +1,5 @@ import { useAppContext } from "~/hooks"; -import { cn, getDaysInMonth } from "~/utils"; +import { cn, getDaysInMonth } from "~/utils/handlers"; interface MonthCardDaysProps { year: number; diff --git a/client/src/components/MonthCardHeader.tsx b/client/src/components/MonthCardHeader.tsx index e355f3a..98bddb7 100644 --- a/client/src/components/MonthCardHeader.tsx +++ b/client/src/components/MonthCardHeader.tsx @@ -1,4 +1,4 @@ -import { cn, getMonthFromIndex } from "~/utils"; +import { cn, getMonthFromIndex } from "~/utils/handlers"; interface MonthCardHeaderProps { year: number; diff --git a/client/src/components/Notice.tsx b/client/src/components/Notice.tsx index 091b364..e251503 100644 --- a/client/src/components/Notice.tsx +++ b/client/src/components/Notice.tsx @@ -1,4 +1,4 @@ -import { cn } from "~/utils"; +import { cn } from "~/utils/handlers"; interface NoticeProps { text: string; diff --git a/client/src/components/Rating.tsx b/client/src/components/Rating.tsx index 0d1a96d..d662a16 100644 --- a/client/src/components/Rating.tsx +++ b/client/src/components/Rating.tsx @@ -1,9 +1,8 @@ import { Button } from "./ui/Button"; import { useMonthContext } from "~/hooks"; -import { STATUSES } from "~/utils"; +import { Status, STATUSES } from "~/utils/types"; import { updateEntryStatus } from "~/api/entries"; -import { Status } from "~/~/models/Entry"; export function Rating() { const { selectedEntryId, setSelectedEntryId, setSelectedRating } = @@ -13,7 +12,7 @@ export function Rating() { if (selectedEntryId) { setSelectedRating(status); - await updateEntryStatus(selectedEntryId, status); + await updateEntryStatus(String(selectedEntryId), status); setSelectedEntryId(null); setSelectedRating(null); diff --git a/client/src/components/Task.tsx b/client/src/components/Task.tsx index b14ecbc..ed8bb4a 100644 --- a/client/src/components/Task.tsx +++ b/client/src/components/Task.tsx @@ -1,22 +1,18 @@ import { useState } from "react"; -import mongoose from "mongoose"; -import { Button } from "./ui/Button"; +import { Button } from "./ui"; import { Entry } from "./Entry"; import { useAppContext, useEntries } from "~/hooks"; import { updateTask } from "~/api/tasks"; -import { ITask } from "~/~/models/Task"; -import { IEntry, Status } from "~/~/models/Entry"; -import { cn } from "~/utils"; - -type MongooseId = mongoose.Types.ObjectId; +import { cn } from "~/utils/handlers"; +import { IEntry, ITask, Status } from "~/utils/types"; interface TaskProps { year: number; month: number; task: ITask; - onDelete: (id: MongooseId, deletedTaskRatings: Status[]) => void; + onDelete: (id: string, deletedTaskRatings: Status[]) => void; } // Task @@ -41,7 +37,7 @@ export function Task({ task, year, month, onDelete }: TaskProps) { return; } - onDelete(task._id, taskRatings); + onDelete(String(task._id), taskRatings); } // Edit title diff --git a/client/src/components/layouts/Header.tsx b/client/src/components/layouts/Header.tsx index 55f8388..63a1e17 100644 --- a/client/src/components/layouts/Header.tsx +++ b/client/src/components/layouts/Header.tsx @@ -1,7 +1,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; -import { Button } from "../ui/Button"; +import { Button } from "../ui"; import { useAuthContext } from "~/hooks"; export function Header() { diff --git a/client/src/components/layouts/Login.tsx b/client/src/components/layouts/Login.tsx index 1a01a99..03f83af 100644 --- a/client/src/components/layouts/Login.tsx +++ b/client/src/components/layouts/Login.tsx @@ -4,8 +4,7 @@ import Link from "next/link"; import axios from "axios"; import jwt, { type JwtPayload } from "jsonwebtoken"; -import { Button } from "~/components/ui/Button"; -import { Input } from "~/components/ui/Input"; +import { Button, Input } from "~/components/ui"; import { login } from "~/api/users"; import { useAuthContext } from "~/hooks"; diff --git a/client/src/components/layouts/Register.tsx b/client/src/components/layouts/Register.tsx index 21111eb..968bcb7 100644 --- a/client/src/components/layouts/Register.tsx +++ b/client/src/components/layouts/Register.tsx @@ -1,9 +1,8 @@ -import Link from "next/link"; import { useRouter } from "next/router"; import { FormEvent, useState } from "react"; +import Link from "next/link"; -import { Button } from "~/components/ui/Button"; -import { Input } from "~/components/ui/Input"; +import { Button, Input } from "~/components/ui"; import { createUser } from "~/api/users"; diff --git a/client/src/components/layouts/Timeline.tsx b/client/src/components/layouts/Timeline.tsx index 10f2469..cc22dd3 100644 --- a/client/src/components/layouts/Timeline.tsx +++ b/client/src/components/layouts/Timeline.tsx @@ -1,8 +1,7 @@ import { MonthCard } from "../MonthCard"; import { Rating } from "../Rating"; -import { useAppContext } from "~/hooks"; -import { useUserYear } from "~/hooks"; +import { useAppContext, useUserYear } from "~/hooks"; export function Timeline() { const { today } = useAppContext(); diff --git a/client/src/components/ui/Button.tsx b/client/src/components/ui/Button.tsx index a73d911..f82d396 100644 --- a/client/src/components/ui/Button.tsx +++ b/client/src/components/ui/Button.tsx @@ -1,6 +1,6 @@ import { ReactNode } from "react"; -import { cn } from "~/utils"; +import { cn } from "~/utils/handlers"; interface ButtonProps { children: ReactNode; diff --git a/client/src/components/ui/Input.tsx b/client/src/components/ui/Input.tsx index e1422ef..8c864ac 100644 --- a/client/src/components/ui/Input.tsx +++ b/client/src/components/ui/Input.tsx @@ -1,5 +1,6 @@ import { ChangeEvent } from "react"; -import { cn } from "~/utils"; + +import { cn } from "~/utils/handlers"; interface InputProps { name: string; diff --git a/client/src/components/ui/index.ts b/client/src/components/ui/index.ts new file mode 100644 index 0000000..b74205b --- /dev/null +++ b/client/src/components/ui/index.ts @@ -0,0 +1,2 @@ +export * from "./Button"; +export * from "./Input"; \ No newline at end of file diff --git a/client/src/context/monthContext.tsx b/client/src/context/monthContext.tsx index a6ea171..7b5dadd 100644 --- a/client/src/context/monthContext.tsx +++ b/client/src/context/monthContext.tsx @@ -1,13 +1,10 @@ import { createContext, ReactNode, useState } from "react"; -import mongoose from "mongoose"; -import { Status } from "~/~/models/Entry"; - -type MongooseId = mongoose.Types.ObjectId; +import { Status } from "~/utils/types"; interface MonthContextProps { - selectedEntryId: MongooseId | null; - setSelectedEntryId: (entry: MongooseId | null) => void; + selectedEntryId: string | null; + setSelectedEntryId: (entry: string | null) => void; selectedRating: Status | null; setSelectedRating: (status: Status | null) => void; } @@ -21,9 +18,7 @@ export const MonthContext = createContext( ); export function MonthContextProvider({ children }: MonthContextProviderProps) { - const [selectedEntryId, setSelectedEntryId] = useState( - null, - ); + const [selectedEntryId, setSelectedEntryId] = useState(null); const [selectedRating, setSelectedRating] = useState(null); const value = { diff --git a/client/src/hooks/context.ts b/client/src/hooks/context.ts new file mode 100644 index 0000000..3aa9031 --- /dev/null +++ b/client/src/hooks/context.ts @@ -0,0 +1,39 @@ +import { useContext } from "react"; + +import { AppContext, AuthContext, MonthContext } from "~/context"; + +// App Context +export function useAppContext() { + const context = useContext(AppContext); + + if (!context) { + throw new Error( + "No context found. App's context must be used within a ContextProvider.", + ); + } + return context; +} + +// Auth Context +export function useAuthContext() { + const context = useContext(AuthContext); + + if (!context) { + throw new Error( + "No context found. App's context must be used within a AuthContextProvider.", + ); + } + return context; +} + +// Month Context +export function useMonthContext() { + const context = useContext(MonthContext); + + if (!context) { + throw new Error( + "No context found. Month context must be used within a ContextProvider.", + ); + } + return context; +} diff --git a/client/src/hooks/index.ts b/client/src/hooks/index.ts index ad93b6d..25dcd51 100644 --- a/client/src/hooks/index.ts +++ b/client/src/hooks/index.ts @@ -1,49 +1,3 @@ -import { useQuery } from "@tanstack/react-query"; - -import { getEntries } from "~/api/entries"; -import { getUserTasks } from "~/api/tasks"; -import { getUserYear } from "~/api/users"; - -export * from "./useAppContext"; -export * from "./useMonthContext"; +export * from "./context"; +export * from "./queries"; export * from "./useMonthRating"; -export * from "./useAuthContext"; - -// Year -export function useUserYear(year: number) { - const { data, isLoading, isError } = useQuery({ - queryKey: ["year"], - queryFn: () => getUserYear(year), - }); - - return { data, isLoading, isError }; -} - -// Tasks -export function useTasks() { - const { data, isLoading, isError } = useQuery({ - queryKey: ["tasks"], - queryFn: () => getUserTasks(), - }); - - return { data, isLoading, isError }; -} - -// Entries -interface UseEntriesProps { - taskId?: string; - year: number; - month: number; - day?: number; -} - -export function useEntries(props: UseEntriesProps) { - const { taskId, year, month, day } = props; - - const { data, isLoading, isError } = useQuery({ - queryKey: ["entires"], - queryFn: () => getEntries({ taskId, year, month, day }), - }); - - return { data, isLoading, isError }; -} diff --git a/client/src/hooks/queries.ts b/client/src/hooks/queries.ts new file mode 100644 index 0000000..af4c2cd --- /dev/null +++ b/client/src/hooks/queries.ts @@ -0,0 +1,45 @@ +import { useQuery } from "@tanstack/react-query"; + +import { getEntries } from "~/api/entries"; +import { getUserTasks } from "~/api/tasks"; +import { getUserYear } from "~/api/users"; + + +// Year +export function useUserYear(year: number) { + const { data, isLoading, isError } = useQuery({ + queryKey: ["year"], + queryFn: () => getUserYear(year), + }); + + return { data, isLoading, isError }; +} + +// Tasks +export function useTasks() { + const { data, isLoading, isError } = useQuery({ + queryKey: ["tasks"], + queryFn: () => getUserTasks(), + }); + + return { data, isLoading, isError }; +} + +// Entries +interface UseEntriesProps { + taskId?: string; + year: number; + month: number; + day?: number; +} + +export function useEntries(props: UseEntriesProps) { + const { taskId, year, month, day } = props; + + const { data, isLoading, isError } = useQuery({ + queryKey: ["entires"], + queryFn: () => getEntries({ taskId, year, month, day }), + }); + + return { data, isLoading, isError }; +} diff --git a/client/src/hooks/useAppContext.tsx b/client/src/hooks/useAppContext.tsx deleted file mode 100644 index dde0bc6..0000000 --- a/client/src/hooks/useAppContext.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from "react"; - -import { AppContext } from "~/context"; - -export function useAppContext() { - const context = useContext(AppContext); - - if (!context) { - throw new Error( - "No context found. App's context must be used within a ContextProvider.", - ); - } - return context; -} diff --git a/client/src/hooks/useAuthContext.tsx b/client/src/hooks/useAuthContext.tsx deleted file mode 100644 index 7f0acd2..0000000 --- a/client/src/hooks/useAuthContext.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from "react"; - -import { AuthContext } from "~/context"; - -export function useAuthContext() { - const context = useContext(AuthContext); - - if (!context) { - throw new Error( - "No context found. App's context must be used within a AuthContextProvider.", - ); - } - return context; -} diff --git a/client/src/hooks/useMonthContext.tsx b/client/src/hooks/useMonthContext.tsx deleted file mode 100644 index 023ef6d..0000000 --- a/client/src/hooks/useMonthContext.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from "react"; - -import { MonthContext } from "~/context"; - -export function useMonthContext() { - const context = useContext(MonthContext); - - if (!context) { - throw new Error( - "No context found. Month context must be used within a ContextProvider.", - ); - } - return context; -} diff --git a/client/src/hooks/useMonthRating.tsx b/client/src/hooks/useMonthRating.tsx index c9fbe35..acc79b9 100644 --- a/client/src/hooks/useMonthRating.tsx +++ b/client/src/hooks/useMonthRating.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from "react"; -import { useMonthContext } from "./useMonthContext"; -import { calculateStatusPercentage } from "~/utils"; -import { IEntry, Status } from "~/~/models/Entry"; +import { useMonthContext } from "./context"; +import { calculateStatusPercentage } from "~/utils/handlers"; +import { IEntry, Status } from "~/utils/types"; interface UseMonthRatingProps { entriesMonthData: IEntry[]; diff --git a/client/src/utils/constants.ts b/client/src/utils/constants.ts index b058124..c1bebe6 100644 --- a/client/src/utils/constants.ts +++ b/client/src/utils/constants.ts @@ -1,6 +1,2 @@ -import { Status } from "~/~/models/Entry"; - -export const STATUSES: Status[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - export const BASE_URL = "http://localhost:5050/api"; diff --git a/client/src/utils/handlers.ts b/client/src/utils/handlers.ts index 46d4fed..b221962 100644 --- a/client/src/utils/handlers.ts +++ b/client/src/utils/handlers.ts @@ -2,7 +2,7 @@ import { AxiosError } from "axios"; import { ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; -import { Status } from "~/~/models/Entry"; +import { Status } from "./types"; // Filter ratings on Delete export function filterDeletedRatings( diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts deleted file mode 100644 index 043cfaa..0000000 --- a/client/src/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./constants"; -export * from "./handlers"; diff --git a/client/src/utils/types.ts b/client/src/utils/types.ts new file mode 100644 index 0000000..351b316 --- /dev/null +++ b/client/src/utils/types.ts @@ -0,0 +1,42 @@ +export type Status = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; +export const STATUSES: Status[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +export interface IEntry { + _id: string; + userId: string; + taskId: string | ITask; + year: number; + month: number; + day: number; + status: Status; + notes?: string; + createdAt?: Date; // string? + updatedAt?: Date; +} + +export interface ITask { + _id: string; + userId: string; + title: string; + entries: string[]; + stopped: boolean; + stoppedAt?: Date; + resumedAt?: Date; + createdAt: Date; + updatedAt: Date; +} + +export interface IUser { + _id: string; + username: string; + email: string; + password: string; + tasks: string[]; + timeline: ITimeline[]; + createdAt: Date; +} + +export interface ITimeline { + year: number; + months: { month: number; tasks: string[] }[]; +}