Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add month % status to the card header #21

Merged
merged 1 commit into from
Sep 15, 2024
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
27 changes: 27 additions & 0 deletions client/src/api/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@ export async function getMonthEntriesByTaskId(
}
}

// Get ALL month entries
export async function getMonthEntries(
userId: string,
year: number,
month: number,
) {
try {
const response: AxiosResponse<IEntry[]> = await axios.get(
`${BASE_URL}/entries/${userId}`,
{
params: {
year,
month,
},
},
);

const data = response.data;

return data;
} catch (err) {
if (err instanceof Error) {
handleRequestError(err);
}
}
}

// All users entries by day
export async function getUserEntriesByDay(
userId: string,
Expand Down
1 change: 0 additions & 1 deletion client/src/components/MonthCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export function MonthCard({ year, month }: MonthCardProps) {
{tasks && tasks?.length > 0 && (
<div className="flex w-full flex-col justify-center gap-2">
<MonthDaysRow year={year} month={month} daysInMonth={daysInMonth} />
{/* <TaskList tasks={tasks} year={year} month={month} /> */}

<div className="space-y-0.5">
{tasks.map((task) => (
Expand Down
23 changes: 15 additions & 8 deletions client/src/components/MonthCardHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useAppContext } from "~/hooks";
import { useDayEntries } from "~/hooks/useDayEntries";
import { useAppContext, useMonthEntries } from "~/hooks";
import { calculateStatusPercentage, cn, getDateDetails } from "~/utils";

interface MonthCardHeaderProps {
Expand All @@ -10,22 +9,30 @@ interface MonthCardHeaderProps {
export function MonthCardHeader({ title, classes }: MonthCardHeaderProps) {
const { userId } = useAppContext();

// Any other date here
const today = new Date();
const { year, month, day } = getDateDetails(today);

const { data, isLoading, error } = useDayEntries({ userId, year, month, day });
const { year, month } = getDateDetails(today);

const statuses = data?.map((entry) => entry.status);
const percentage = calculateStatusPercentage(statuses);
const { data: monthEntries, isLoading: isEntriesLoading } = useMonthEntries({
userId,
year,
month,
});

const tasks = new Set(monthEntries?.map((entry) => entry.taskId));

const monthStatuses = monthEntries?.map((entry) => entry.status);
const monthPercentage = calculateStatusPercentage(monthStatuses);

return (
<div className={cn("flex w-full items-center justify-between", classes)}>
<h2 className="text-xl font-semibold capitalize">{title}</h2>

<div className="space-x-1 text-sm">
<span>{`${data?.length} tasks`}</span>
<span>{`${tasks.size} tasks`}</span>
<span>•</span>
<span>{`${percentage}% today 🔥`}</span>
<span>{`${monthPercentage}% month 🔥`}</span>
</div>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/MonthDaysRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function MonthDaysRow({ year, month, daysInMonth }: MonthDaysRowProps) {
const today = new Date();

const currentDate = today.getDate();
const currentMonth = today.getMonth() + 1;
const currentMonth = today.getMonth();
const currentYear = today.getFullYear();

const isCurrentYearAndMonth = year === currentYear && month === currentMonth;
Expand All @@ -27,7 +27,7 @@ export function MonthDaysRow({ year, month, daysInMonth }: MonthDaysRowProps) {
"flex size-6 shrink-0 items-center justify-center rounded-sm bg-transparent text-xs text-stone-400",
isCurrentYearAndMonth &&
currentDate === i + 1 &&
"rounded-full bg-stone-50 text-stone-800",
"rounded-full bg-stone-50 text-stone-800 font-medium",
)}
>
{i + 1}
Expand Down
32 changes: 32 additions & 0 deletions client/src/components/Rating.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Button } from "./ui/Button";

import { useAppContext } from "~/hooks";
import { STATUSES } from "~/utils";
import { updateEntryStatus } from "~/api/entries";
import { Status } from "~/~/models/Entry";


export function Rating() {
const { selectedEntryId, setSelectedEntryId } = useAppContext();

async function handleSetRating(status: Status) {
if (selectedEntryId) {
await updateEntryStatus(selectedEntryId, status);
setSelectedEntryId(null);
}
}

return (
<div className="flex gap-2 rounded-lg bg-brown-100/20 p-4">
{STATUSES.map((status) => (
<Button
key={status}
classes="flex size-10 items-center justify-center rounded-md bg-brown-100 text-brown-800 hover:bg-brown-800 hover:text-brown-50"
onClick={() => handleSetRating(status as Status)}
>
{status}
</Button>
))}
</div>
);
}
32 changes: 1 addition & 31 deletions client/src/components/layouts/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { Button } from "../ui/Button";
import { MonthCard } from "../MonthCard";

import { useAppContext } from "~/hooks";
import { updateEntryStatus } from "~/api/entries";
import { Status } from "~/~/models/Entry";
import { STATUSES } from "~/utils";
import { Rating } from "../Rating";

export function Dashboard() {
const year = new Date().getFullYear();
Expand All @@ -17,28 +12,3 @@ export function Dashboard() {
</div>
);
}

export function Rating() {
const { selectedEntryId, setSelectedEntryId } = useAppContext();

async function handleSetRating(status: Status) {
if (selectedEntryId) {
await updateEntryStatus(selectedEntryId, status);
setSelectedEntryId(null);
}
}

return (
<div className="flex gap-2 rounded-lg bg-brown-100/20 p-4">
{STATUSES.map((status) => (
<Button
key={status}
classes="flex size-10 items-center justify-center rounded-md bg-brown-100 text-brown-800 hover:bg-brown-800 hover:text-brown-50"
onClick={() => handleSetRating(status as Status)}
>
{status}
</Button>
))}
</div>
);
}
17 changes: 5 additions & 12 deletions client/src/hooks/useMonthEntries.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useEffect, useState } from "react";
import mongoose from "mongoose";

import { getMonthEntriesByTaskId } from "~/api/entries";
import { getMonthEntries, getMonthEntriesByTaskId } from "~/api/entries";
import { IEntry } from "~/~/models/Entry";

interface IUseEntriesProps {
userId: string;
taskId: mongoose.Types.ObjectId | undefined;
taskId?: mongoose.Types.ObjectId;
year: number;
month: number;
}
Expand All @@ -23,17 +23,10 @@ export function useMonthEntries(props: IUseEntriesProps) {
setIsLoading(true);
setError(false);

if (!taskId) {
return;
}

try {
const entries = await getMonthEntriesByTaskId(
userId,
taskId,
year,
month,
);
const entries = taskId
? await getMonthEntriesByTaskId(userId, taskId, year, month)
: await getMonthEntries(userId, year, month);

setData(entries);
setIsLoading(false);
Expand Down
2 changes: 1 addition & 1 deletion client/src/utils/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function calculateStatusPercentage(statuses: Status[] | undefined) {
const totalScore = statuses.reduce<number>((sum, status) => sum + status, 0);
const percentage = (totalScore / totalPossibleScore) * 100;

return percentage;
return Math.round(percentage);
}

// Get date details
Expand Down
8 changes: 7 additions & 1 deletion server/src/api/entries.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import express from "express";

import { getUserEntriesByDay, getMonthEntriesByTaskId } from "../controllers/getEntries.js";
import {
getUserEntriesByDay,
getMonthEntriesByTaskId,
getMonthEntries,
} from "../controllers/getEntries.js";

import { updateEntryStatus } from "../controllers/updateEntry.js";

const router = express.Router();

// Get
router.route("/day/:userId").get(getUserEntriesByDay);
router.route("/:userId/:taskId").get(getMonthEntriesByTaskId);
router.route("/:userId").get(getMonthEntries);

// Update
router.route("/:entryId").patch(updateEntryStatus);
Expand Down
30 changes: 30 additions & 0 deletions server/src/controllers/getEntries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,36 @@ import { Request, Response } from "express";
import { Entry } from "../models/Entry.js";
import { getMonthFromIndex } from "../utils/handlers.js";

// Month entries
export async function getMonthEntries(req: Request, res: Response) {
const { userId } = req.params;
const { year, month } = req.query;

if (!year || !month) {
return res.status(500).json({
message: "Some parameters are missing: year, month.",
});
}

try {
const entries = await Entry.find({
userId,
year: Number(year),
month: getMonthFromIndex(Number(month) - 1),
}).exec();

return res.json(entries);
} catch (err) {
if (err instanceof Error) {
console.log("🔴 Error:", err.message);

return res.status(500).json({
message: "Failed to fetch user's month entries.",
});
}
}
}

// Month entries by taskId
export async function getMonthEntriesByTaskId(req: Request, res: Response) {
const { userId, taskId } = req.params;
Expand Down
Loading