From 2b3e4aa1fcb2e4eba755c87a44bf60ea1870568e Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sat, 19 Nov 2022 17:50:17 +0530 Subject: [PATCH 1/5] app: version updated to v0.0.7 --- src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9534a24..27f5232 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ }, "package": { "productName": "Habit Watcher", - "version": "0.0.6" + "version": "0.0.7" }, "tauri": { "allowlist": { From 47968d1b7a06d61c935614af5b13fe46d603d1d7 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sat, 19 Nov 2022 17:50:41 +0530 Subject: [PATCH 2/5] feat: Habit Card UI updated --- src/components/Home/HabbitCard.tsx | 110 ++++++++++++++--------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/components/Home/HabbitCard.tsx b/src/components/Home/HabbitCard.tsx index 36188cf..550574a 100644 --- a/src/components/Home/HabbitCard.tsx +++ b/src/components/Home/HabbitCard.tsx @@ -57,11 +57,6 @@ export const HabbitCard = (view: HabbitCardProps) => { onSuccess: (data) => { client.invalidateQueries(["fetchAllHabbits"]) setShowing(data.confetti) - showNotification({ - title: "Success", - message: data.message, - color: "teal", - }) }, onError: () => { showNotification({ @@ -97,46 +92,49 @@ export const HabbitCard = (view: HabbitCardProps) => { return ( - - - {view.habbit.name} - -
- - - - - - - - - - - - { - view.setHabbit(view.habbit) - view.setIsOpen(true) - }} - > - Rename Habbit - - - Danger zone - { - deleteHabbitMutation(view.habbit.id) - }}> - Remove Habbit - - - - -
-
+ + + + {view.habbit.name} + +
+ + + + + + + + + + + Summary + + { + view.setHabbit(view.habbit) + view.setIsOpen(true) + }} + > + Rename Habbit + + + Danger zone + { + deleteHabbitMutation(view.habbit.id) + }}> + Remove Habbit + + + + +
+
+
{ view.stats.map((stat) => ()) @@ -150,16 +148,18 @@ export const HabbitCard = (view: HabbitCardProps) => { panelAttributes={undefined} panelColors={panelColors} /> - - { - setChecked(e.currentTarget.checked); - checkHabbitMutation(view.habbit.id); - }} - /> + + { + setChecked(e.currentTarget.checked); + checkHabbitMutation(view.habbit.id); + }} + /> +
); }; From f72828e05ae17d80625d2af11dc2b74a3514bfe7 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sat, 26 Nov 2022 23:51:24 +0530 Subject: [PATCH 3/5] fix: long and current steak bug fixed --- src/components/Home/HabbitCard.tsx | 6 +- src/components/Summary/index.tsx | 32 ++++++++ src/main.tsx | 5 ++ src/models/habbit.ts | 5 ++ src/services/storage.ts | 118 ++++++++++++++++++++++++----- src/summary.tsx | 9 +++ 6 files changed, 156 insertions(+), 19 deletions(-) create mode 100644 src/components/Summary/index.tsx create mode 100644 src/summary.tsx diff --git a/src/components/Home/HabbitCard.tsx b/src/components/Home/HabbitCard.tsx index 550574a..3d20236 100644 --- a/src/components/Home/HabbitCard.tsx +++ b/src/components/Home/HabbitCard.tsx @@ -3,6 +3,7 @@ import { showNotification } from "@mantine/notifications"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import React from "react"; import Calendar from "react-github-contribution-calendar"; +import { useNavigate } from "react-router-dom"; import { useConfetti } from "../../hooks/useConfetti"; import { Habbit, HabbitView } from "../../models/habbit"; import { checkHabbit, deleteHabbit } from "../../services/storage"; @@ -48,6 +49,7 @@ export const HabbitCard = (view: HabbitCardProps) => { } = useConfetti() const client = useQueryClient() const { classes } = useStyles(); + const navigate = useNavigate() const [checked, setChecked] = React.useState(view.isChecked); @@ -109,7 +111,9 @@ export const HabbitCard = (view: HabbitCardProps) => { - + navigate(`/summary/${view.habbit.id}`)} + > Summary { + + const params = useParams() + const navigate = useNavigate() + + const fetchData = async () => { + const id = params.id as string + const response = await getHabitByID(+id) + return response + } + + const { data } = useQuery(['fetchHabitByID', params.id], fetchData, { + refetchOnWindowFocus: false, + enabled: Boolean(params.id), + onError: () => navigate('/') + }) + + console.log(data) + + return ( +
+ { + params.id + } +
+ ) +} \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index c863dd2..cd3d989 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -10,6 +10,7 @@ import { NewHabitPage } from "./new-habit"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { NotificationsProvider } from "@mantine/notifications"; import { ConfettiProvider } from "./hooks/useConfetti"; +import { SummaryPage } from "./summary"; const queryClient = new QueryClient(); const router = createBrowserRouter([ { @@ -21,6 +22,10 @@ const router = createBrowserRouter([ path: "/new", element: , }, + { + path: "/summary/:id", + element: + } ], errorElement: , }, diff --git a/src/models/habbit.ts b/src/models/habbit.ts index f8c9ea0..51422aa 100644 --- a/src/models/habbit.ts +++ b/src/models/habbit.ts @@ -29,3 +29,8 @@ export interface HabbitView { isChecked: boolean; untilDate: Date; } + +export interface SingleHabitView { + habbit: Habbit; + stats: HabbitStats[]; +} \ No newline at end of file diff --git a/src/services/storage.ts b/src/services/storage.ts index 2f3d2b6..faebf37 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -4,6 +4,7 @@ import type { HabbitContributions, HabbitStats, HabbitView, + SingleHabitView, } from "../models/habbit"; import moment from "moment"; import Database from "tauri-plugin-sql-api"; @@ -68,20 +69,12 @@ export async function getAllhabbitsWithStats() { value: missingDays > 0 ? missingDays : 0, }); // find the current streak - let currentStreak = 0; - let lastLogDate = moment(); - for (const log of logs) { - const logDate = moment(log.created_at); - const diff = logDate.diff(lastLogDate, "days"); - if (diff > 1) { - break; - } - currentStreak++; - lastLogDate = logDate; - } + + const groupeDates = Object.keys(contributions); + stats.push({ name: "Current Streak", - value: currentStreak, + value: currentStreak(groupeDates), }); const today = moment().format("YYYY-MM-DD"); @@ -113,7 +106,7 @@ export async function checkHabbit(id: number) { return { message: "You have unchecked the habit", confetti: false, - } + }; } // kinda weird but it works const created_at = moment(new Date()).format("YYYY-MM-DD HH:mm:ss"); @@ -121,16 +114,14 @@ export async function checkHabbit(id: number) { "INSERT INTO habbit_log (habbit_id, created_at) VALUES (?, ?)", [id, created_at], ); - // check all habbits completed today + // check all habbits completed today const allHabbits = await getAllhabbitsWithStats(); - const allHabbitsCompleted = allHabbits.every(habbit => habbit.isChecked); - - + const allHabbitsCompleted = allHabbits.every((habbit) => habbit.isChecked); return { message: "Awesome! You have checked the habit", confetti: allHabbitsCompleted, - } + }; } export async function deleteHabbit(id: number) { @@ -141,8 +132,99 @@ export async function deleteHabbit(id: number) { return "Habit deleted"; } +export async function getHabitByID(id: number): Promise { + await load; + const hbt: Habbit[] = await db.select("SELECT * FROM habbit WHERE id = ?", [ + id, + ]); + if (hbt.length === 0) { + throw new Error("Habit not found"); + } + const habbit = hbt[0]; + const logs: HabbitLog[] = await db.select( + "SELECT * FROM habbit_log WHERE habbit_id = ?", + [habbit.id], + ); + + const stats: HabbitStats[] = []; + + stats.push({ + name: "Total Completed", + value: logs.length, + }); + + const contributions: Record = {}; + + logs.forEach((log) => { + const date = moment(log.created_at).format("YYYY-MM-DD"); + contributions[date] = 1; + }); + + const groupeDates = Object.keys(contributions); + + stats.push({ + name: "Longest Streak", + value: longestStreak(groupeDates), + }); + + stats.push({ + name: "Current Streak", + value: currentStreak(groupeDates), + }); + + return { + habbit, + stats, + }; +} + export async function updateHabbit(id: number, name: string) { await load; await db.execute("UPDATE habbit SET name = ? WHERE id = ?", [name, id]); return "Habit updated"; } + +const longestStreak = (dates: string[]) => { + // sort dates + const sortedDates = dates.sort((a, b) => { + return moment(a).diff(moment(b)); + }); + if (sortedDates.length === 0) { + return 0; + } + const lastDay = moment(sortedDates[0]); + let count = 1; + for (let i = 1; i < sortedDates.length; i++) { + const currentDay = moment(sortedDates[i]); + if (currentDay.diff(lastDay, "days") === 1) { + count++; + } + lastDay.add(1, "days"); + } + return count; +}; + + +const currentStreak = (dates: string[]) => { + // sort dates + const sortedDates = dates.sort((a, b) => { + return moment(new Date(a)).diff(moment(new Date(b))); + }).reverse(); + + let count = 0; + let currentDay = moment() + + + for (const day of sortedDates) { + const date = moment(day) + if (date.diff(currentDay, "days") === 0) { + count++ + } else { + break + } + currentDay.subtract(1, "days") + } + + + return count; +}; diff --git a/src/summary.tsx b/src/summary.tsx new file mode 100644 index 0000000..1ee5de4 --- /dev/null +++ b/src/summary.tsx @@ -0,0 +1,9 @@ +import { SummaryBody } from "./components/Summary"; + +export const SummaryPage = () => { + return ( + <> + + + ); +}; From 3e279e210c8a2915c0a52dffc021c028c0db719f Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Mon, 28 Nov 2022 21:57:30 +0530 Subject: [PATCH 4/5] fix: some new fixes --- src/components/Common/HabitLoading.tsx | 12 ++++ src/components/Home/HabbitList.tsx | 68 +++++++++------------ src/components/Summary/SummartStatsCard.tsx | 31 ++++++++++ src/components/Summary/index.tsx | 39 ++++++++++-- src/models/habbit.ts | 1 + src/services/storage.ts | 3 + 6 files changed, 109 insertions(+), 45 deletions(-) create mode 100644 src/components/Common/HabitLoading.tsx create mode 100644 src/components/Summary/SummartStatsCard.tsx diff --git a/src/components/Common/HabitLoading.tsx b/src/components/Common/HabitLoading.tsx new file mode 100644 index 0000000..4600152 --- /dev/null +++ b/src/components/Common/HabitLoading.tsx @@ -0,0 +1,12 @@ +import { Skeleton } from "@mantine/core"; + +export const HabitLoading = () => { + return ( +
+ + + + +
+ ); +}; diff --git a/src/components/Home/HabbitList.tsx b/src/components/Home/HabbitList.tsx index 6a12df9..f9fa700 100644 --- a/src/components/Home/HabbitList.tsx +++ b/src/components/Home/HabbitList.tsx @@ -5,6 +5,7 @@ import { useQuery } from "@tanstack/react-query"; import { Habbit } from "../../models/habbit"; import React from "react"; import { UpdaetHabit } from "./UpdateHabit"; +import { HabitLoading } from "../Common/HabitLoading"; export const HabbitList = () => { const fetchHabbit = async () => { @@ -14,25 +15,13 @@ export const HabbitList = () => { const { data, status } = useQuery(["fetchAllHabbits"], fetchHabbit); - - const [habbit, setHabbit] = React.useState(null) + const [habbit, setHabbit] = React.useState(null); const [open, setOpen] = React.useState(false); - - return ( <> - - { - status === "loading" ? (
- - - - -
) : null - } - { - status === "success" ? - + {status === "loading" ? : null} + {status === "success" ? ( + { { maxWidth: 600, cols: 1, spacing: "sm" }, ]} > - { - } - { - data.length > 0 ? data.map((habbit) => ()) - : - Oh no! You don't have any habbits yet. Create one now! - - } + { } + {data.length > 0 ? ( + data.map((habbit) => ( + + )) + ) : ( + + Oh no! You don't have any habbits yet. Create one now! + + )} setOpen(false)} title="Update Habit" > - { - habbit ? setOpen(false)} /> : null - } + {habbit ? ( + setOpen(false)} /> + ) : null} - : null - } - { - status === "error" ? (
- - There was an error fetching your habbits - + + ) : null} + {status === "error" ? ( +
+ There was an error fetching your habbits
- ) : null - } + ) : null} ); }; diff --git a/src/components/Summary/SummartStatsCard.tsx b/src/components/Summary/SummartStatsCard.tsx new file mode 100644 index 0000000..3024a4c --- /dev/null +++ b/src/components/Summary/SummartStatsCard.tsx @@ -0,0 +1,31 @@ +import { Group, Paper, Text, createStyles } from "@mantine/core"; +import { HabbitStats } from "../../models/habbit"; + +const useStyles = createStyles((theme) => ({ + statsValue: { + fontSize: 40, + } +})) + +export const SummaryStatsCard = (stat: HabbitStats) => { + const { classes } = useStyles() + return ( + + +
+ + {stat.name} + + + {stat.value} + +
+
+
+ ); +}; diff --git a/src/components/Summary/index.tsx b/src/components/Summary/index.tsx index 0be43e5..b992ce0 100644 --- a/src/components/Summary/index.tsx +++ b/src/components/Summary/index.tsx @@ -2,9 +2,19 @@ import { useQuery } from "@tanstack/react-query"; import React from "react"; import { useNavigate, useParams } from "react-router-dom"; import { getHabitByID } from "../../services/storage"; +import { createStyles, Group, Paper, Text, ThemeIcon, SimpleGrid } from '@mantine/core'; +import { HabitLoading } from "../Common/HabitLoading"; +import { SummaryStatsCard } from "./SummartStatsCard"; +import { BackBtn } from "../Common/BackBtn"; +const useStyles = createStyles((theme) => ({ + root: { + padding: theme.spacing.xl * 1.5, + }, +})); -export const SummaryBody = () => { +export const SummaryBody = () => { + const { classes } = useStyles(); const params = useParams() const navigate = useNavigate() @@ -14,19 +24,36 @@ export const SummaryBody = () => { return response } - const { data } = useQuery(['fetchHabitByID', params.id], fetchData, { + const { data, status } = useQuery(['fetchHabitByID', params.id], fetchData, { refetchOnWindowFocus: false, enabled: Boolean(params.id), onError: () => navigate('/') }) - console.log(data) return (
- { - params.id - } + {status === "loading" ? : null} + {status === "error" ? Something went wrong : null} + {status === "success" ? ( +
+ + + + + + {data.habbit.name} + + + + + + { + data.stats.map((stat, i) => ()) + } + +
+ ) : null}
) } \ No newline at end of file diff --git a/src/models/habbit.ts b/src/models/habbit.ts index 51422aa..0d120a8 100644 --- a/src/models/habbit.ts +++ b/src/models/habbit.ts @@ -15,6 +15,7 @@ export interface HabbitLog { export interface HabbitStats { name: string; value: number; + description?: string; } export interface HabbitContributions { diff --git a/src/services/storage.ts b/src/services/storage.ts index faebf37..2f617f2 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -151,6 +151,7 @@ export async function getHabitByID(id: number): Promise { stats.push({ name: "Total Completed", value: logs.length, + description: "Total number of times you have completed this habit", }); const contributions: Record = {}; @@ -165,11 +166,13 @@ export async function getHabitByID(id: number): Promise { stats.push({ name: "Longest Streak", value: longestStreak(groupeDates), + description: "Longest streak of days you have completed this habit", }); stats.push({ name: "Current Streak", value: currentStreak(groupeDates), + description: "Current streak of days you have completed this habit", }); return { From 052e04ffe2faf83ce25313efe46787d27de1a869 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sun, 11 Dec 2022 19:53:55 +0530 Subject: [PATCH 5/5] bug fix --- src/services/storage.ts | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/services/storage.ts b/src/services/storage.ts index 2f617f2..9f40981 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -189,25 +189,34 @@ export async function updateHabbit(id: number, name: string) { const longestStreak = (dates: string[]) => { // sort dates - const sortedDates = dates.sort((a, b) => { - return moment(a).diff(moment(b)); - }); - if (sortedDates.length === 0) { - return 0; - } - const lastDay = moment(sortedDates[0]); - let count = 1; - for (let i = 1; i < sortedDates.length; i++) { - const currentDay = moment(sortedDates[i]); - if (currentDay.diff(lastDay, "days") === 1) { - count++; + dates.sort() + let longestStreak = 0; + let currentStreak = 1; + + for (let i = 1; i < dates.length; i++) { + // Check if the current date is consecutive with the previous date + if (isConsecutive(dates[i], dates[i - 1])) { + // If it is, increment the current streak + currentStreak++; + } else { + // If it isn't, reset the current streak to 1 + currentStreak = 1; } - lastDay.add(1, "days"); + + // Update the longest streak if necessary + longestStreak = Math.max(longestStreak, currentStreak); } - return count; + return longestStreak; }; +function isConsecutive(date1: string, date2: string) { + const d1 = new Date(date1); + const d2 = new Date(date2); + const timeDiff = d1.getTime() - d2.getTime(); + const diffDays = timeDiff / (1000 * 3600 * 24); + return diffDays === 1; +} const currentStreak = (dates: string[]) => { // sort dates const sortedDates = dates.sort((a, b) => { @@ -231,3 +240,10 @@ const currentStreak = (dates: string[]) => { return count; }; + + +interface Options { + startDate: string; + endDate: string; +} +