diff --git a/.eslintrc.json b/.eslintrc.json index b3f2bf44d..9c1f95874 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,7 +6,6 @@ }, "extends": [ "next/core-web-vitals", - "plugin:storybook/recommended", "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended" diff --git a/.storybook/main.ts b/.storybook/main.ts deleted file mode 100644 index 24c7f7e27..000000000 --- a/.storybook/main.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { StorybookConfig } from "@storybook/nextjs"; -import path from "path"; - -const config: StorybookConfig = { - stories: [ - "../stories/**/*.mdx", - "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)", - ], - addons: [ - "@storybook/addon-links", - "@storybook/addon-essentials", - "@storybook/addon-onboarding", - "@storybook/addon-interactions", - "@storybook/addon-mdx-gfm" - ], - framework: { - name: "@storybook/nextjs", - options: {}, - }, - docs: { - autodocs: "tag", - }, - webpackFinal: async (config) => ({ - ...config, - resolve: { - ...config.resolve, - alias: { - ...config.resolve?.alias, - "@": path.resolve(__dirname, "../"), - }, - }, - }), - staticDirs: ["../public"], -}; -export default config; diff --git a/.storybook/preview.ts b/.storybook/preview.ts deleted file mode 100644 index 7d917742a..000000000 --- a/.storybook/preview.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Preview } from "@storybook/react"; -import "../styles/globals.css"; - -const preview: Preview = { - parameters: { - // actions: { argTypesRegex: "^on[A-Z].*" }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/i, - }, - }, - }, -}; - -export default preview; diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 2e369e8ae..932e6c9d6 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,8 @@ "recommendations": [ "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", - "davidanson.vscode-markdownlint" + "davidanson.vscode-markdownlint", + "bradlc.vscode-tailwindcss", + "austenc.tailwind-docs" ] } diff --git a/api/useDayplans.ts b/api/useDayplans.ts index d6326e6d5..3c17ac5e7 100644 --- a/api/useDayplans.ts +++ b/api/useDayplans.ts @@ -1,6 +1,6 @@ import { type Schema } from "@/amplify/data/resource"; import { Context } from "@/contexts/ContextContext"; -import { sortByDate } from "@/helpers/functional"; +import { toISODateString } from "@/helpers/functional"; import { SelectionSet, generateClient } from "aws-amplify/data"; import { useEffect, useState } from "react"; import useSWR from "swr"; @@ -33,7 +33,7 @@ export type DayPlanTodo = { type DayPlan = { id: string; - day: string; + day: Date; dayGoal: string; context: Context; done: boolean; @@ -81,7 +81,7 @@ const mapDayPlan: (dayplan: DayPlanData) => DayPlan = ({ todos, }) => ({ id, - day, + day: new Date(day), dayGoal, context: context || "work", done: !!done, @@ -140,7 +140,7 @@ const fetchDayPlans = (context?: Context) => async () => { if (!context) return; return (await fetchDayPlansWithToken(context)) ?.map(mapDayPlan) - .sort((a, b) => sortByDate(true)([a.day, b.day])); + .sort((a, b) => b.day.getTime() - a.day.getTime()); }; export type CreateTodoFn = (props: { @@ -244,7 +244,7 @@ const useDayPlans = (context?: Context) => { }; const createDayPlan = async ( - day: string, + day: Date, dayGoal: string, context?: Context ) => { @@ -261,7 +261,7 @@ const useDayPlans = (context?: Context) => { }; mutate([newDayPlan, ...(dayPlans || [])], false); const { data, errors } = await client.models.DayPlan.create({ - day, + day: toISODateString(day), dayGoal, done: false, context, @@ -271,15 +271,42 @@ const useDayPlans = (context?: Context) => { mutate([{ ...newDayPlan, id: data.id }, ...(dayPlans || [])]); }; + const undoDayplanCompletion = async (dayplan: Schema["DayPlan"]["type"]) => { + const updatedDayPlans: DayPlan[] = [ + ...(dayPlans?.filter(({ id }) => id !== dayplan.id) || []), + { + id: dayplan.id, + context: dayplan.context, + day: new Date(dayplan.day), + dayGoal: dayplan.dayGoal, + done: false, + nonprojectTasks: [], + projectTasks: [], + todos: [], + }, + ]; + mutate(updatedDayPlans, false); + const { data, errors } = await client.models.DayPlan.update({ + id: dayplan.id, + done: false, + }); + if (errors) handleApiErrors(errors, "Error undoing completion of day plan"); + if (!data) return; + mutate(updatedDayPlans); + return data; + }; + const completeDayPlan = async (dayPlanId: string) => { const updatedDayPlans = dayPlans?.filter(({ id }) => id !== dayPlanId); mutate(updatedDayPlans, false); - const { errors } = await client.models.DayPlan.update({ + const { data, errors } = await client.models.DayPlan.update({ id: dayPlanId, done: true, }); if (errors) handleApiErrors(errors, "Error completing day plan"); + if (!data) return; mutate(updatedDayPlans); + return data; }; const createTodo: CreateTodoFn = async ({ todo, dayplanId, projectId }) => { @@ -330,6 +357,7 @@ const useDayPlans = (context?: Context) => { loadingDayPlans, createDayPlan, completeDayPlan, + undoDayplanCompletion, createTodo, switchTodoDone, migrateLegacyTasks, diff --git a/components.json b/components.json new file mode 100644 index 000000000..b208ec385 --- /dev/null +++ b/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "styles/globals.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/components/CategoryTitle.module.css b/components/CategoryTitle.module.css deleted file mode 100644 index b7d0f2f28..000000000 --- a/components/CategoryTitle.module.css +++ /dev/null @@ -1,78 +0,0 @@ -@media (min-width: 40em) { - .alignCenterOnMedium { - text-align: center; - } -} - -.content { - position: sticky; - top: 5rem; - background-color: var(--color-bg-sheet-transparent); - z-index: 20; -} - -@media (max-width: 40em) { - .content { - top: 4rem; - padding-bottom: 1rem; - } -} - -.content h1, -.content textarea { - font-size: var(--font-size-xx-large); - font-weight: bold; - line-height: 1; - padding: 0; - margin-top: 0; -} - -.isEditable:hover { - cursor: pointer; - box-shadow: inset 0 -1px 0 var(--color-subtle); -} - -.content textarea { - background: transparent; - border: none; - outline: none; - width: 100%; - box-sizing: border-box; - vertical-align: top; - overflow: hidden; - resize: none; - margin-bottom: 2rem; - box-shadow: inset 0 -1px 0 var(--color-text-secondary); -} - -.action { - position: absolute; - display: flex; - z-index: 7; - font-size: var(--font-size-medium); - top: -0.4rem; - right: 0; -} - -.backAction { - font-size: var(--font-size-x-large); - color: var(--color-btn-secondary); - cursor: pointer; -} - -.backAction:hover { - color: var(--color-btn); -} - -@media (max-width: 39.99em) { - .content h1, - .content textarea { - font-size: var(--font-size-x-large); - margin-top: 0.4rem; - margin-bottom: 0; - } - - .action { - font-size: var(--font-size-small); - } -} diff --git a/components/CategoryTitle.tsx b/components/CategoryTitle.tsx index 479fe9d8b..a58608d46 100644 --- a/components/CategoryTitle.tsx +++ b/components/CategoryTitle.tsx @@ -1,8 +1,7 @@ import { useRouter } from "next/router"; import { ChangeEvent, FC, useEffect, useRef, useState } from "react"; import { IoChevronBackOutline } from "react-icons/io5"; -import styles from "./CategoryTitle.module.css"; -import SubmitButton from "./ui-elements/buttons/submit-button"; +import { Button } from "./ui/button"; export type CategoryTitleProps = { title?: string; @@ -46,47 +45,54 @@ const CategoryTitle: FC = (props) => { }; return ( -
- {(props.drawBackBtn || props.onBackBtnClick) && ( -
router.back() - } - > - -
- )} - {title && - (props.saveTitle && isEditing ? ( -