From 74348009990896331593d81d7d88967ebc0cf366 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 2 Aug 2023 12:09:53 +0530 Subject: [PATCH 01/10] chore: show message if dragging unjoined project (#1763) --- .../project/single-sidebar-project.tsx | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/app/components/project/single-sidebar-project.tsx b/apps/app/components/project/single-sidebar-project.tsx index acc1f493e62..ef1b6771e70 100644 --- a/apps/app/components/project/single-sidebar-project.tsx +++ b/apps/app/components/project/single-sidebar-project.tsx @@ -137,21 +137,30 @@ export const SingleSidebarProject: React.FC = ({ {({ open }) => ( <>
{provided && ( - + + )} Date: Wed, 2 Aug 2023 13:38:45 +0530 Subject: [PATCH 02/10] fix: invalid project selection in create issue modal (#1766) --- apps/app/components/issues/modal.tsx | 32 +++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/app/components/issues/modal.tsx b/apps/app/components/issues/modal.tsx index be3b556a122..d7180b7616f 100644 --- a/apps/app/components/issues/modal.tsx +++ b/apps/app/components/issues/modal.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useCallback } from "react"; import { useRouter } from "next/router"; @@ -98,20 +98,36 @@ export const CreateUpdateIssueModal: React.FC = ({ assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""], }; + const onClose = useCallback(() => { + handleClose(); + setActiveProject(null); + }, [handleClose]); + useEffect(() => { + // if modal is closed, reset active project to null + // and return to avoid activeProject being set to some other project + if (!isOpen) { + setActiveProject(null); + return; + } + + // if data is present, set active project to the project of the + // issue. This has more priority than the project in the url. if (data && data.project) { setActiveProject(data.project); return; } + // if data is not present, set active project to the project + // in the url. This has the least priority. if (projects && projects.length > 0 && !activeProject) setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null); - }, [activeProject, data, projectId, projects]); + }, [activeProject, data, projectId, projects, isOpen]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") { - handleClose(); + onClose(); } }; @@ -119,7 +135,7 @@ export const CreateUpdateIssueModal: React.FC = ({ return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [handleClose]); + }, [onClose]); const addIssueToCycle = async (issueId: string, cycleId: string) => { if (!workspaceSlug || !activeProject) return; @@ -267,7 +283,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }); }); - if (!createMore) handleClose(); + if (!createMore) onClose(); }; const updateIssue = async (payload: Partial) => { @@ -286,7 +302,7 @@ export const CreateUpdateIssueModal: React.FC = ({ if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module); - if (!createMore) handleClose(); + if (!createMore) onClose(); setToastAlert({ type: "success", @@ -324,7 +340,7 @@ export const CreateUpdateIssueModal: React.FC = ({ return ( - handleClose()}> + = ({ initialData={data ?? prePopulateData} createMore={createMore} setCreateMore={setCreateMore} - handleClose={handleClose} + handleClose={onClose} projectId={activeProject ?? ""} setActiveProject={setActiveProject} status={data ? true : false} From 584192faba6297bc006573c5c47038543230ab20 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:21:26 +0530 Subject: [PATCH 03/10] style: sidebar project list improvement (#1767) --- apps/app/components/project/sidebar-list.tsx | 2 +- .../project/single-sidebar-project.tsx | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/app/components/project/sidebar-list.tsx b/apps/app/components/project/sidebar-list.tsx index 5790e7c0bc4..1bb3711fcab 100644 --- a/apps/app/components/project/sidebar-list.tsx +++ b/apps/app/components/project/sidebar-list.tsx @@ -130,7 +130,7 @@ export const ProjectSidebarList: FC = () => { data={projectToDelete} user={user} /> -
+
{(provided) => ( diff --git a/apps/app/components/project/single-sidebar-project.tsx b/apps/app/components/project/single-sidebar-project.tsx index ef1b6771e70..8545739f79c 100644 --- a/apps/app/components/project/single-sidebar-project.tsx +++ b/apps/app/components/project/single-sidebar-project.tsx @@ -170,17 +170,17 @@ export const SingleSidebarProject: React.FC = ({ > -
+
{project.emoji ? ( {renderEmoji(project.emoji)} ) : project.icon_prop ? ( -
+
{renderEmoji(project.icon_prop)}
) : ( @@ -190,19 +190,15 @@ export const SingleSidebarProject: React.FC = ({ )} {!sidebarCollapse && ( -

- {truncateText(project.name, 15)} +

+ {project.name}

)}
{!sidebarCollapse && ( @@ -211,7 +207,7 @@ export const SingleSidebarProject: React.FC = ({ {!sidebarCollapse && ( - + {!shortContextMenu && ( From 87a920174e2705fbe92f3c33eca4f6237052dd9c Mon Sep 17 00:00:00 2001 From: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:21:48 +0530 Subject: [PATCH 04/10] fix: comment reaction mutation (#1768) --- apps/app/hooks/use-comment-reaction.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/app/hooks/use-comment-reaction.tsx b/apps/app/hooks/use-comment-reaction.tsx index 16469f66a4d..6deb4d9fb18 100644 --- a/apps/app/hooks/use-comment-reaction.tsx +++ b/apps/app/hooks/use-comment-reaction.tsx @@ -70,7 +70,8 @@ const useCommentReaction = ( mutateCommentReactions( (prevData) => - prevData?.filter((r) => r.actor !== user?.user?.id || r.reaction !== reaction) || [] + prevData?.filter((r) => r.actor !== user?.user?.id || r.reaction !== reaction) || [], + false ); await reactionService.deleteIssueCommentReaction( From a66dcb94198343aadcaeadec4636b8d82abfab4d Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:42:24 +0530 Subject: [PATCH 05/10] fix: user profiles n plus 1 (#1765) --- apiserver/plane/api/views/workspace.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apiserver/plane/api/views/workspace.py b/apiserver/plane/api/views/workspace.py index b195cedb1ef..a862c0b4c3f 100644 --- a/apiserver/plane/api/views/workspace.py +++ b/apiserver/plane/api/views/workspace.py @@ -75,6 +75,7 @@ Label, WorkspaceMember, CycleIssue, + IssueReaction, ) from plane.api.permissions import ( WorkSpaceBasePermission, @@ -1321,6 +1322,12 @@ def get(self, request, slug, user_id): ) .select_related("project", "workspace", "state", "parent") .prefetch_related("assignees", "labels") + .prefetch_related( + Prefetch( + "issue_reactions", + queryset=IssueReaction.objects.select_related("actor"), + ) + ) .order_by("-created_at") .annotate( link_count=IssueLink.objects.filter(issue=OuterRef("id")) From 9a298962917beb72ca60ccae746d2a1769afd7df Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:42:47 +0530 Subject: [PATCH 06/10] fix: bulk issue import (#1773) --- apiserver/plane/api/views/importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/plane/api/views/importer.py b/apiserver/plane/api/views/importer.py index 63e2d38a13e..4fc7ad48357 100644 --- a/apiserver/plane/api/views/importer.py +++ b/apiserver/plane/api/views/importer.py @@ -332,7 +332,7 @@ def post(self, request, slug, project_id, service): # if there is no default state assign any random state if default_state is None: default_state = State.objects.filter( - ~Q(name="Triage"), sproject_id=project_id + ~Q(name="Triage"), project_id=project_id ).first() # Get the maximum sequence_id From c16b0daa22459086be480dcd4d9dde31ca8274f8 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:45:34 +0530 Subject: [PATCH 07/10] style: profile activity (#1771) * style: profile activity comment log styling * chore: profile feed activity refactor * style: sidebar project list --- apps/app/components/core/feeds.tsx | 342 ------------------ apps/app/components/core/index.ts | 1 - .../project/single-sidebar-project.tsx | 8 +- .../[workspaceSlug]/me/profile/activity.tsx | 207 ++++++++++- 4 files changed, 200 insertions(+), 358 deletions(-) delete mode 100644 apps/app/components/core/feeds.tsx diff --git a/apps/app/components/core/feeds.tsx b/apps/app/components/core/feeds.tsx deleted file mode 100644 index 2924ec45685..00000000000 --- a/apps/app/components/core/feeds.tsx +++ /dev/null @@ -1,342 +0,0 @@ -import React from "react"; - -import { useRouter } from "next/router"; - -import Link from "next/link"; - -// icons -import { - ArrowTopRightOnSquareIcon, - ChatBubbleLeftEllipsisIcon, - Squares2X2Icon, -} from "@heroicons/react/24/outline"; -import { BlockedIcon, BlockerIcon } from "components/icons"; -import { Icon } from "components/ui"; -// helpers -import { renderShortDateWithYearFormat, timeAgo } from "helpers/date-time.helper"; -import { addSpaceIfCamelCase } from "helpers/string.helper"; -// types -import RemirrorRichTextEditor from "components/rich-text-editor"; - -const activityDetails: { - [key: string]: { - message?: string; - icon: JSX.Element; - }; -} = { - assignee: { - message: "removed the assignee", - icon:
From a1ae338c3719213d5b6b6d5e7b3f30d20972fff2 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:47:36 +0530 Subject: [PATCH 08/10] chore: add non existing states for project entities (#1770) --- apps/app/components/ui/empty-state.tsx | 4 +- .../projects/[projectId]/cycles/[cycleId].tsx | 79 ++++++++++++------- .../projects/[projectId]/issues/[issueId].tsx | 22 +++++- .../[projectId]/modules/[moduleId].tsx | 53 ++++++++----- .../projects/[projectId]/pages/[pageId].tsx | 69 +++++++++------- .../projects/[projectId]/views/[viewId].tsx | 24 ++++-- 6 files changed, 164 insertions(+), 87 deletions(-) diff --git a/apps/app/components/ui/empty-state.tsx b/apps/app/components/ui/empty-state.tsx index 26b621d985a..098c3f15293 100644 --- a/apps/app/components/ui/empty-state.tsx +++ b/apps/app/components/ui/empty-state.tsx @@ -7,7 +7,7 @@ import { PrimaryButton } from "components/ui"; type Props = { title: string; - description: React.ReactNode | string; + description?: React.ReactNode; image: any; primaryButton?: { icon?: any; @@ -34,7 +34,7 @@ export const EmptyState: React.FC = ({
{primaryButton?.text}
{title}
-

{description}

+ {description &&

{description}

}
{primaryButton && ( diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx index 0da8f797c44..de6ad561ee0 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx @@ -22,8 +22,10 @@ import useUserAuth from "hooks/use-user-auth"; // components import { AnalyticsProjectModal } from "components/analytics"; // ui -import { CustomMenu, SecondaryButton } from "components/ui"; +import { CustomMenu, EmptyState, SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; +// images +import emptyCycle from "public/empty-state/cycle.svg"; // helpers import { truncateText } from "helpers/string.helper"; import { getDateRangeStatus } from "helpers/date-time.helper"; @@ -52,14 +54,14 @@ const SingleCycle: React.FC = () => { : null ); - const { data: cycleDetails } = useSWR( - cycleId ? CYCLE_DETAILS(cycleId as string) : null, + const { data: cycleDetails, error } = useSWR( + workspaceSlug && projectId && cycleId ? CYCLE_DETAILS(cycleId.toString()) : null, workspaceSlug && projectId && cycleId ? () => cycleServices.getCycleDetails( - workspaceSlug as string, - projectId as string, - cycleId as string + workspaceSlug.toString(), + projectId.toString(), + cycleId.toString() ) : null ); @@ -159,31 +161,48 @@ const SingleCycle: React.FC = () => {
} > - setTransferIssuesModal(false)} - isOpen={transferIssuesModal} - /> - setAnalyticsModal(false)} /> -
- {cycleStatus === "completed" && ( - setTransferIssuesModal(true)} /> - )} - router.push(`/${workspaceSlug}/projects/${projectId}/cycles`), + }} /> -
- + ) : ( + <> + setTransferIssuesModal(false)} + isOpen={transferIssuesModal} + /> + setAnalyticsModal(false)} + /> +
+ {cycleStatus === "completed" && ( + setTransferIssuesModal(true)} /> + )} + +
+ + + )} ); diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx index d5f7c8ec622..35697ee0fd7 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx @@ -15,8 +15,10 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { IssueDetailsSidebar, IssueMainContent } from "components/issues"; // ui -import { Loader } from "components/ui"; +import { EmptyState, Loader } from "components/ui"; import { Breadcrumbs } from "components/breadcrumbs"; +// images +import emptyIssue from "public/empty-state/issue.svg"; // types import { IIssue } from "types"; import type { NextPage } from "next"; @@ -45,7 +47,11 @@ const IssueDetailsPage: NextPage = () => { const { user } = useUserAuth(); - const { data: issueDetails, mutate: mutateIssueDetails } = useSWR( + const { + data: issueDetails, + mutate: mutateIssueDetails, + error, + } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, workspaceSlug && projectId && issueId ? () => @@ -125,7 +131,17 @@ const IssueDetailsPage: NextPage = () => { } > - {issueDetails && projectId ? ( + {error ? ( + router.push(`/${workspaceSlug}/projects/${projectId}/issues`), + }} + /> + ) : issueDetails && projectId ? (
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx index 71c3bb6554f..57319262625 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx @@ -20,8 +20,10 @@ import { ExistingIssuesListModal, IssuesFilterView, IssuesView } from "component import { ModuleDetailsSidebar } from "components/modules"; import { AnalyticsProjectModal } from "components/analytics"; // ui -import { CustomMenu, SecondaryButton } from "components/ui"; +import { CustomMenu, EmptyState, SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; +// images +import emptyModule from "public/empty-state/module.svg"; // helpers import { truncateText } from "helpers/string.helper"; // types @@ -60,7 +62,7 @@ const SingleModule: React.FC = () => { : null ); - const { data: moduleDetails } = useSWR( + const { data: moduleDetails, error } = useSWR( moduleId ? MODULE_DETAILS(moduleId as string) : null, workspaceSlug && projectId ? () => @@ -162,22 +164,37 @@ const SingleModule: React.FC = () => {
} > - setAnalyticsModal(false)} /> - -
- -
- - + {error ? ( + router.push(`/${workspaceSlug}/projects/${projectId}/modules`), + }} + /> + ) : ( + <> + setAnalyticsModal(false)} + /> +
+ +
+ + + )} ); diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index b26be661efe..ed52f447ad7 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { useRouter } from "next/router"; @@ -28,7 +28,16 @@ import { CreateLabelModal } from "components/labels"; import { CreateBlock } from "components/pages/create-block"; // ui import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -import { CustomSearchSelect, Loader, TextArea, ToggleSwitch, Tooltip } from "components/ui"; +import { + CustomSearchSelect, + EmptyState, + Loader, + TextArea, + ToggleSwitch, + Tooltip, +} from "components/ui"; +// images +import emptyPage from "public/empty-state/page.svg"; // icons import { ArrowLeftIcon, @@ -40,7 +49,7 @@ import { XMarkIcon, ChevronDownIcon, } from "@heroicons/react/24/outline"; -import { ColorPalletteIcon, ClipboardIcon } from "components/icons"; +import { ColorPalletteIcon } from "components/icons"; // helpers import { render24HourFormatTime, renderShortDate } from "helpers/date-time.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper"; @@ -82,7 +91,7 @@ const SinglePage: NextPage = () => { : null ); - const { data: pageDetails } = useSWR( + const { data: pageDetails, error } = useSWR( workspaceSlug && projectId && pageId ? PAGE_DETAILS(pageId as string) : null, workspaceSlug && projectId ? () => @@ -267,13 +276,6 @@ const SinglePage: NextPage = () => { ); }; - const handleNewBlock = useCallback(() => { - setCreateBlockForm(true); - scrollToRef.current?.scrollIntoView({ - behavior: "smooth", - }); - }, [setCreateBlockForm, scrollToRef]); - const handleShowBlockToggle = async () => { if (!workspaceSlug || !projectId) return; @@ -311,22 +313,21 @@ const SinglePage: NextPage = () => { }); }; - const options = - labels?.map((label) => ({ - value: label.id, - query: label.name, - content: ( -
- - {label.name} -
- ), - })) ?? []; + const options = labels?.map((label) => ({ + value: label.id, + query: label.name, + content: ( +
+ + {label.name} +
+ ), + })); useEffect(() => { if (!pageDetails) return; @@ -346,11 +347,21 @@ const SinglePage: NextPage = () => { breadcrumbs={ - + } > - {pageDetails ? ( + {error ? ( + router.push(`/${workspaceSlug}/projects/${projectId}/pages`), + }} + /> + ) : pageDetails ? (
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx index b1cbf97f2e4..3597f113fa0 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx @@ -12,11 +12,13 @@ import { IssueViewContextProvider } from "contexts/issue-view.context"; // components import { IssuesFilterView, IssuesView } from "components/core"; // ui -import { CustomMenu, PrimaryButton } from "components/ui"; +import { CustomMenu, EmptyState, PrimaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; import { StackedLayersIcon } from "components/icons"; +// images +import emptyView from "public/empty-state/view.svg"; // helpers import { truncateText } from "helpers/string.helper"; // fetch-keys @@ -40,7 +42,7 @@ const SingleView: React.FC = () => { : null ); - const { data: viewDetails } = useSWR( + const { data: viewDetails, error } = useSWR( workspaceSlug && projectId && viewId ? VIEW_DETAILS(viewId as string) : null, workspaceSlug && projectId && viewId ? () => @@ -101,9 +103,21 @@ const SingleView: React.FC = () => {
} > -
- -
+ {error ? ( + router.push(`/${workspaceSlug}/projects/${projectId}/views`), + }} + /> + ) : ( +
+ +
+ )} ); From 5aad6c71da63a8a5c35bde2aa876c86304759f7b Mon Sep 17 00:00:00 2001 From: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:23:55 +0530 Subject: [PATCH 09/10] fix: notification read status being toggled when click on link (#1769) --- .../notifications/notification-card.tsx | 4 +++- .../notifications/notification-popover.tsx | 4 +++- apps/app/hooks/use-user-notifications.tsx | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/app/components/notifications/notification-card.tsx b/apps/app/components/notifications/notification-card.tsx index 71c2d676ac6..3a0d2f9b88d 100644 --- a/apps/app/components/notifications/notification-card.tsx +++ b/apps/app/components/notifications/notification-card.tsx @@ -27,6 +27,7 @@ import { snoozeOptions } from "constants/notification"; type NotificationCardProps = { notification: IUserNotification; markNotificationReadStatus: (notificationId: string) => Promise; + markNotificationReadStatusToggle: (notificationId: string) => Promise; markNotificationArchivedStatus: (notificationId: string) => Promise; setSelectedNotificationForSnooze: (notificationId: string) => void; markSnoozeNotification: (notificationId: string, dateTime?: Date | undefined) => Promise; @@ -36,6 +37,7 @@ export const NotificationCard: React.FC = (props) => { const { notification, markNotificationReadStatus, + markNotificationReadStatusToggle, markNotificationArchivedStatus, setSelectedNotificationForSnooze, markSnoozeNotification, @@ -159,7 +161,7 @@ export const NotificationCard: React.FC = (props) => { name: notification.read_at ? "Mark as unread" : "Mark as read", icon: "chat_bubble", onClick: () => { - markNotificationReadStatus(notification.id).then(() => { + markNotificationReadStatusToggle(notification.id).then(() => { setToastAlert({ title: notification.read_at ? "Notification marked as unread" diff --git a/apps/app/components/notifications/notification-popover.tsx b/apps/app/components/notifications/notification-popover.tsx index 0e57c472c3c..cd8c50bd298 100644 --- a/apps/app/components/notifications/notification-popover.tsx +++ b/apps/app/components/notifications/notification-popover.tsx @@ -38,6 +38,7 @@ export const NotificationPopover = () => { notificationMutate, markNotificationArchivedStatus, markNotificationReadStatus, + markNotificationAsRead, markSnoozeNotification, notificationCount, totalNotificationCount, @@ -128,7 +129,8 @@ export const NotificationPopover = () => { key={notification.id} notification={notification} markNotificationArchivedStatus={markNotificationArchivedStatus} - markNotificationReadStatus={markNotificationReadStatus} + markNotificationReadStatus={markNotificationAsRead} + markNotificationReadStatusToggle={markNotificationReadStatus} setSelectedNotificationForSnooze={setSelectedNotificationForSnooze} markSnoozeNotification={markSnoozeNotification} /> diff --git a/apps/app/hooks/use-user-notifications.tsx b/apps/app/hooks/use-user-notifications.tsx index 33c2d4e65a6..868633db04f 100644 --- a/apps/app/hooks/use-user-notifications.tsx +++ b/apps/app/hooks/use-user-notifications.tsx @@ -185,6 +185,26 @@ const useUserNotification = () => { } }; + const markNotificationAsRead = async (notificationId: string) => { + if (!workspaceSlug) return; + + const isRead = + notifications?.find((notification) => notification.id === notificationId)?.read_at !== null; + + if (isRead) return; + + mutateNotification(notificationId, { read_at: new Date() }); + handleReadMutation("read"); + + await userNotificationServices + .markUserNotificationAsRead(workspaceSlug.toString(), notificationId) + .catch(() => { + throw new Error("Something went wrong"); + }); + + mutateNotificationCount(); + }; + const markNotificationArchivedStatus = async (notificationId: string) => { if (!workspaceSlug) return; const isArchived = @@ -283,6 +303,7 @@ const useUserNotification = () => { hasMore, isRefreshing, setFetchNotifications, + markNotificationAsRead, }; }; From 97c3fb40e77d2e26caad7d4f4bdaf31713828fd3 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:01:31 +0530 Subject: [PATCH 10/10] fix: custom theme persisting after signing out (#1780) * fix: custom theme persistence * chore: remove console logs * fix: build error * fix: change theme from command k --- .../change-interface-theme.tsx | 38 ++- .../core/theme/custom-theme-selector.tsx | 2 + .../components/core/theme/theme-switch.tsx | 221 ++++++++++-------- .../components/workspace/sidebar-dropdown.tsx | 6 +- apps/app/constants/themes.ts | 10 + apps/app/contexts/theme.context.tsx | 23 +- apps/app/helpers/theme.helper.ts | 60 ++--- .../me/profile/preferences.tsx | 11 +- apps/app/pages/_app.tsx | 2 +- apps/app/pages/colors.tsx | 143 ------------ apps/app/pages/index.tsx | 34 ++- apps/app/pages/magic-sign-in.tsx | 13 +- apps/app/pages/onboarding.tsx | 7 +- apps/app/pages/reset-password.tsx | 8 + apps/app/pages/sign-up.tsx | 8 + apps/app/services/authentication.service.ts | 7 +- apps/app/types/users.d.ts | 1 + 17 files changed, 287 insertions(+), 307 deletions(-) delete mode 100644 apps/app/pages/colors.tsx diff --git a/apps/app/components/command-palette/change-interface-theme.tsx b/apps/app/components/command-palette/change-interface-theme.tsx index b2b43c6704d..b34212b7f91 100644 --- a/apps/app/components/command-palette/change-interface-theme.tsx +++ b/apps/app/components/command-palette/change-interface-theme.tsx @@ -5,6 +5,8 @@ import { Command } from "cmdk"; import { THEMES_OBJ } from "constants/themes"; import { useTheme } from "next-themes"; import { SettingIcon } from "components/icons"; +import userService from "services/user.service"; +import useUser from "hooks/use-user"; type Props = { setIsPaletteOpen: Dispatch>; @@ -12,24 +14,50 @@ type Props = { export const ChangeInterfaceTheme: React.FC = ({ setIsPaletteOpen }) => { const [mounted, setMounted] = useState(false); + const { setTheme } = useTheme(); + const { user, mutateUser } = useUser(); + + const updateUserTheme = (newTheme: string) => { + if (!user) return; + + setTheme(newTheme); + + mutateUser((prevData) => { + if (!prevData) return prevData; + + return { + ...prevData, + theme: { + ...prevData.theme, + theme: newTheme, + }, + }; + }, false); + + userService.updateUser({ + theme: { + ...user.theme, + theme: newTheme, + }, + }); + }; + // useEffect only runs on the client, so now we can safely show the UI useEffect(() => { setMounted(true); }, []); - if (!mounted) { - return null; - } + if (!mounted) return null; return ( <> - {THEMES_OBJ.map((theme) => ( + {THEMES_OBJ.filter((t) => t.value !== "custom").map((theme) => ( { - setTheme(theme.value); + updateUserTheme(theme.value); setIsPaletteOpen(false); }} className="focus:outline-none" diff --git a/apps/app/components/core/theme/custom-theme-selector.tsx b/apps/app/components/core/theme/custom-theme-selector.tsx index 40450ee2c76..668083b590e 100644 --- a/apps/app/components/core/theme/custom-theme-selector.tsx +++ b/apps/app/components/core/theme/custom-theme-selector.tsx @@ -28,6 +28,7 @@ const defaultValues: ICustomTheme = { sidebarText: "#c5c5c5", darkPalette: false, palette: "", + theme: "custom", }; export const CustomThemeSelector: React.FC = ({ preLoadedData }) => { @@ -56,6 +57,7 @@ export const CustomThemeSelector: React.FC = ({ preLoadedData }) => { sidebarText: formData.sidebarText, darkPalette: darkPalette, palette: `${formData.background},${formData.text},${formData.primary},${formData.sidebarBackground},${formData.sidebarText}`, + theme: "custom", }; await userService diff --git a/apps/app/components/core/theme/theme-switch.tsx b/apps/app/components/core/theme/theme-switch.tsx index 39b570bc53e..8ac950b8ce0 100644 --- a/apps/app/components/core/theme/theme-switch.tsx +++ b/apps/app/components/core/theme/theme-switch.tsx @@ -1,142 +1,161 @@ -import { useState, useEffect, Dispatch, SetStateAction } from "react"; +import { useState, useEffect } from "react"; +// next-themes import { useTheme } from "next-themes"; - +// services +import userService from "services/user.service"; +// hooks +import useUser from "hooks/use-user"; // constants import { THEMES_OBJ } from "constants/themes"; // ui import { CustomSelect } from "components/ui"; // types -import { ICustomTheme, IUser } from "types"; +import { ICustomTheme } from "types"; +import { unsetCustomCssVariables } from "helpers/theme.helper"; type Props = { - user: IUser | undefined; - setPreLoadedData: Dispatch>; + setPreLoadedData: React.Dispatch>; customThemeSelectorOptions: boolean; - setCustomThemeSelectorOptions: Dispatch>; + setCustomThemeSelectorOptions: React.Dispatch>; }; export const ThemeSwitch: React.FC = ({ - user, setPreLoadedData, customThemeSelectorOptions, setCustomThemeSelectorOptions, }) => { const [mounted, setMounted] = useState(false); + const { theme, setTheme } = useTheme(); + const { user, mutateUser } = useUser(); + + const updateUserTheme = (newTheme: string) => { + if (!user) return; + + setTheme(newTheme); + + mutateUser((prevData) => { + if (!prevData) return prevData; + + return { + ...prevData, + theme: { + ...prevData.theme, + theme: newTheme, + }, + }; + }, false); + + userService.updateUser({ + theme: { + ...user.theme, + theme: newTheme, + }, + }); + }; + // useEffect only runs on the client, so now we can safely show the UI useEffect(() => { setMounted(true); }, []); - if (!mounted) { - return null; - } + if (!mounted) return null; const currentThemeObj = THEMES_OBJ.find((t) => t.value === theme); return ( - <> - + +
-
-
-
- {currentThemeObj.label} + /> +
- ) : ( - "Select your theme" - ) - } - onChange={({ value, type }: { value: string; type: string }) => { - if (value === "custom") { - if (user?.theme.palette) { - setPreLoadedData({ - background: user.theme.background !== "" ? user.theme.background : "#0d101b", - text: user.theme.text !== "" ? user.theme.text : "#c5c5c5", - primary: user.theme.primary !== "" ? user.theme.primary : "#3f76ff", - sidebarBackground: - user.theme.sidebarBackground !== "" ? user.theme.sidebarBackground : "#0d101b", - sidebarText: user.theme.sidebarText !== "" ? user.theme.sidebarText : "#c5c5c5", - darkPalette: false, - palette: - user.theme.palette !== ",,,," - ? user.theme.palette - : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", - }); - } - - if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true); - } else { - if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false); - - for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) { - document.documentElement.style.removeProperty(`--color-background-${i}`); - document.documentElement.style.removeProperty(`--color-text-${i}`); - document.documentElement.style.removeProperty(`--color-border-${i}`); - document.documentElement.style.removeProperty(`--color-primary-${i}`); - document.documentElement.style.removeProperty(`--color-sidebar-background-${i}`); - document.documentElement.style.removeProperty(`--color-sidebar-text-${i}`); - document.documentElement.style.removeProperty(`--color-sidebar-border-${i}`); - } + {currentThemeObj.label} +
+ ) : ( + "Select your theme" + ) + } + onChange={({ value, type }: { value: string; type: string }) => { + if (value === "custom") { + if (user?.theme.palette) { + setPreLoadedData({ + background: user.theme.background !== "" ? user.theme.background : "#0d101b", + text: user.theme.text !== "" ? user.theme.text : "#c5c5c5", + primary: user.theme.primary !== "" ? user.theme.primary : "#3f76ff", + sidebarBackground: + user.theme.sidebarBackground !== "" ? user.theme.sidebarBackground : "#0d101b", + sidebarText: user.theme.sidebarText !== "" ? user.theme.sidebarText : "#c5c5c5", + darkPalette: false, + palette: + user.theme.palette !== ",,,," + ? user.theme.palette + : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", + theme: "custom", + }); } - setTheme(value); - document.documentElement.style.setProperty("color-scheme", type); - }} - input - width="w-full" - position="right" - > - {THEMES_OBJ.map(({ value, label, type, icon }) => ( - -
+ if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true); + } else { + if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false); + unsetCustomCssVariables(); + } + + updateUserTheme(value); + document.documentElement.style.setProperty("--color-scheme", type); + }} + input + width="w-full" + position="right" + > + {THEMES_OBJ.map(({ value, label, type, icon }) => ( + +
+
+
-
-
-
- {label} + />
- - ))} - - + {label} +
+ + ))} + ); }; diff --git a/apps/app/components/workspace/sidebar-dropdown.tsx b/apps/app/components/workspace/sidebar-dropdown.tsx index 3b9aa97eb9a..7a43cfb74b9 100644 --- a/apps/app/components/workspace/sidebar-dropdown.tsx +++ b/apps/app/components/workspace/sidebar-dropdown.tsx @@ -3,10 +3,10 @@ import { Fragment } from "react"; import { useRouter } from "next/router"; import Link from "next/link"; -// next-themes -import { useTheme } from "next-themes"; // headless ui import { Menu, Transition } from "@headlessui/react"; +// next-themes +import { useTheme } from "next-themes"; // hooks import useUser from "hooks/use-user"; import useThemeHook from "hooks/use-theme"; @@ -91,7 +91,7 @@ export const WorkspaceSidebarDropdown = () => { .then(() => { mutateUser(undefined); router.push("/"); - setTheme("dark"); + setTheme("system"); }) .catch(() => setToastAlert({ diff --git a/apps/app/constants/themes.ts b/apps/app/constants/themes.ts index 78420843a64..74b74caba8b 100644 --- a/apps/app/constants/themes.ts +++ b/apps/app/constants/themes.ts @@ -1,6 +1,16 @@ export const THEMES = ["light", "dark", "light-contrast", "dark-contrast", "custom"]; export const THEMES_OBJ = [ + { + value: "system", + label: "System Preference", + type: "light", + icon: { + border: "#DEE2E6", + color1: "#FAFAFA", + color2: "#3F76FF", + }, + }, { value: "light", label: "Light", diff --git a/apps/app/contexts/theme.context.tsx b/apps/app/contexts/theme.context.tsx index 0f548912538..d338b9b6b87 100644 --- a/apps/app/contexts/theme.context.tsx +++ b/apps/app/contexts/theme.context.tsx @@ -11,7 +11,7 @@ import projectService from "services/project.service"; // fetch-keys import { USER_PROJECT_VIEW } from "constants/fetch-keys"; // helper -import { applyTheme } from "helpers/theme.helper"; +import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper"; // constants export const themeContext = createContext({} as ContextType); @@ -92,15 +92,18 @@ export const ThemeContextProvider: React.FC<{ children: React.ReactNode }> = ({ useEffect(() => { const theme = localStorage.getItem("theme"); - if (theme && theme === "custom") { - if (user && user.theme.palette) { - applyTheme( - user.theme.palette !== ",,,," - ? user.theme.palette - : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", - user.theme.darkPalette - ); - } + + if (theme) { + if (theme === "custom") { + if (user && user.theme.palette) { + applyTheme( + user.theme.palette !== ",,,," + ? user.theme.palette + : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", + user.theme.darkPalette + ); + } + } else unsetCustomCssVariables(); } }, [user]); diff --git a/apps/app/helpers/theme.helper.ts b/apps/app/helpers/theme.helper.ts index 993a6b9ea21..8a521bc31cd 100644 --- a/apps/app/helpers/theme.helper.ts +++ b/apps/app/helpers/theme.helper.ts @@ -60,6 +60,7 @@ const calculateShades = (hexValue: string): TShades => { }; export const applyTheme = (palette: string, isDarkPalette: boolean) => { + const dom = document?.querySelector("[data-theme='custom']"); // palette: [bg, text, primary, sidebarBg, sidebarText] const values: string[] = palette.split(","); values.push(isDarkPalette ? "dark" : "light"); @@ -79,41 +80,40 @@ export const applyTheme = (palette: string, isDarkPalette: boolean) => { const sidebarBackgroundRgbValues = `${sidebarBackgroundShades[shade].r}, ${sidebarBackgroundShades[shade].g}, ${sidebarBackgroundShades[shade].b}`; const sidebarTextRgbValues = `${sidebarTextShades[shade].r}, ${sidebarTextShades[shade].g}, ${sidebarTextShades[shade].b}`; - document - .querySelector("[data-theme='custom']") - ?.style.setProperty(`--color-background-${shade}`, bgRgbValues); - document - .querySelector("[data-theme='custom']") - ?.style.setProperty(`--color-text-${shade}`, textRgbValues); - document - .querySelector("[data-theme='custom']") - ?.style.setProperty(`--color-primary-${shade}`, primaryRgbValues); - document - .querySelector("[data-theme='custom']") - ?.style.setProperty(`--color-sidebar-background-${shade}`, sidebarBackgroundRgbValues); - document - .querySelector("[data-theme='custom']") - ?.style.setProperty(`--color-sidebar-text-${shade}`, sidebarTextRgbValues); + dom?.style.setProperty(`--color-background-${shade}`, bgRgbValues); + dom?.style.setProperty(`--color-text-${shade}`, textRgbValues); + dom?.style.setProperty(`--color-primary-${shade}`, primaryRgbValues); + dom?.style.setProperty(`--color-sidebar-background-${shade}`, sidebarBackgroundRgbValues); + dom?.style.setProperty(`--color-sidebar-text-${shade}`, sidebarTextRgbValues); if (i >= 100 && i <= 400) { const borderShade = i === 100 ? 70 : i === 200 ? 80 : i === 300 ? 90 : 100; - document - .querySelector("[data-theme='custom']") - ?.style.setProperty( - `--color-border-${shade}`, - `${bgShades[borderShade].r}, ${bgShades[borderShade].g}, ${bgShades[borderShade].b}` - ); - document - .querySelector("[data-theme='custom']") - ?.style.setProperty( - `--color-sidebar-border-${shade}`, - `${sidebarBackgroundShades[borderShade].r}, ${sidebarBackgroundShades[borderShade].g}, ${sidebarBackgroundShades[borderShade].b}` - ); + dom?.style.setProperty( + `--color-border-${shade}`, + `${bgShades[borderShade].r}, ${bgShades[borderShade].g}, ${bgShades[borderShade].b}` + ); + dom?.style.setProperty( + `--color-sidebar-border-${shade}`, + `${sidebarBackgroundShades[borderShade].r}, ${sidebarBackgroundShades[borderShade].g}, ${sidebarBackgroundShades[borderShade].b}` + ); } } - document - .querySelector("[data-theme='custom']") - ?.style.setProperty("--color-scheme", values[5]); + dom?.style.setProperty("--color-scheme", values[5]); +}; + +export const unsetCustomCssVariables = () => { + for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) { + const dom = document.querySelector("[data-theme='custom']"); + + dom?.style.removeProperty(`--color-background-${i}`); + dom?.style.removeProperty(`--color-text-${i}`); + dom?.style.removeProperty(`--color-border-${i}`); + dom?.style.removeProperty(`--color-primary-${i}`); + dom?.style.removeProperty(`--color-sidebar-background-${i}`); + dom?.style.removeProperty(`--color-sidebar-text-${i}`); + dom?.style.removeProperty(`--color-sidebar-border-${i}`); + dom?.style.removeProperty("--color-scheme"); + } }; diff --git a/apps/app/pages/[workspaceSlug]/me/profile/preferences.tsx b/apps/app/pages/[workspaceSlug]/me/profile/preferences.tsx index 605131aa4b9..61e743fc3a6 100644 --- a/apps/app/pages/[workspaceSlug]/me/profile/preferences.tsx +++ b/apps/app/pages/[workspaceSlug]/me/profile/preferences.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from "react"; -import { useTheme } from "next-themes"; +// next-themes +import { useTheme } from "next-themes"; // hooks import useUserAuth from "hooks/use-user-auth"; // layouts @@ -15,11 +16,13 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { ICustomTheme } from "types"; const ProfilePreferences = () => { - const { user: myProfile } = useUserAuth(); - const { theme } = useTheme(); const [customThemeSelectorOptions, setCustomThemeSelectorOptions] = useState(false); const [preLoadedData, setPreLoadedData] = useState(null); + const { theme } = useTheme(); + + const { user: myProfile } = useUserAuth(); + useEffect(() => { if (theme === "custom") { if (myProfile?.theme.palette) @@ -37,6 +40,7 @@ const ProfilePreferences = () => { myProfile.theme.palette !== ",,,," ? myProfile.theme.palette : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", + theme: "custom", }); if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true); } @@ -71,7 +75,6 @@ const ProfilePreferences = () => {
- + diff --git a/apps/app/pages/colors.tsx b/apps/app/pages/colors.tsx deleted file mode 100644 index d52e2cf41ce..00000000000 --- a/apps/app/pages/colors.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import React from "react"; - -// layouts -import DefaultLayout from "layouts/default-layout"; -import { UserAuthorizationLayout } from "layouts/auth-layout/user-authorization-wrapper"; -// types -import type { NextPage } from "next"; - -const Colors: NextPage = () => ( - - -
-
- Primary: -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Background: -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Text: -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Sidebar Background: -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Sidebar Text: -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -); - -export default Colors; diff --git a/apps/app/pages/index.tsx b/apps/app/pages/index.tsx index 6cef211c03a..f9e4d984400 100644 --- a/apps/app/pages/index.tsx +++ b/apps/app/pages/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import Image from "next/image"; @@ -22,6 +22,8 @@ import { import { Spinner } from "components/ui"; // images import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png"; +import { useTheme } from "next-themes"; +import { ICurrentUserResponse, IUser } from "types"; // types type EmailPasswordFormValues = { email: string; @@ -34,6 +36,12 @@ const HomePage: NextPage = () => { const { setToastAlert } = useToast(); + const { setTheme } = useTheme(); + + const changeTheme = (user: IUser) => { + setTheme(user.theme.theme ?? "system"); + }; + const handleGoogleSignIn = async ({ clientId, credential }: any) => { try { if (clientId && credential) { @@ -43,7 +51,10 @@ const HomePage: NextPage = () => { clientId, }; const response = await authenticationService.socialAuth(socialAuthPayload); - if (response && response?.user) mutateUser(); + if (response && response?.user) { + mutateUser(); + changeTheme(response.user); + } } else { throw Error("Cant find credentials"); } @@ -66,7 +77,10 @@ const HomePage: NextPage = () => { clientId: process.env.NEXT_PUBLIC_GITHUB_ID, }; const response = await authenticationService.socialAuth(socialAuthPayload); - if (response && response?.user) mutateUser(); + if (response && response?.user) { + mutateUser(); + changeTheme(response.user); + } } else { throw Error("Cant find credentials"); } @@ -85,7 +99,10 @@ const HomePage: NextPage = () => { .emailLogin(formData) .then((response) => { try { - if (response) mutateUser(); + if (response) { + mutateUser(); + changeTheme(response.user); + } } catch (err: any) { setToastAlert({ type: "error", @@ -109,7 +126,10 @@ const HomePage: NextPage = () => { const handleEmailCodeSignIn = async (response: any) => { try { - if (response) mutateUser(); + if (response) { + mutateUser(); + changeTheme(response.user); + } } catch (err: any) { setToastAlert({ type: "error", @@ -120,6 +140,10 @@ const HomePage: NextPage = () => { } }; + useEffect(() => { + setTheme("system"); + }, [setTheme]); + return ( {isLoading ? ( diff --git a/apps/app/pages/magic-sign-in.tsx b/apps/app/pages/magic-sign-in.tsx index c959764a2f7..7de298d3926 100644 --- a/apps/app/pages/magic-sign-in.tsx +++ b/apps/app/pages/magic-sign-in.tsx @@ -1,6 +1,9 @@ import React, { useState, useEffect } from "react"; -// next imports + import { useRouter } from "next/router"; + +// next-themes +import { useTheme } from "next-themes"; // layouts import DefaultLayout from "layouts/default-layout"; // services @@ -17,11 +20,17 @@ const MagicSignIn: NextPage = () => { const { setToastAlert } = useToast(); - const { user, isLoading, mutateUser } = useUserAuth("sign-in"); + const { setTheme } = useTheme(); + + const { mutateUser } = useUserAuth("sign-in"); const [isSigningIn, setIsSigningIn] = useState(false); const [errorSigningIn, setErrorSignIn] = useState(); + useEffect(() => { + setTheme("system"); + }, [setTheme]); + useEffect(() => { setIsSigningIn(() => false); setErrorSignIn(() => undefined); diff --git a/apps/app/pages/onboarding.tsx b/apps/app/pages/onboarding.tsx index 217584dd0fe..51148b19e35 100644 --- a/apps/app/pages/onboarding.tsx +++ b/apps/app/pages/onboarding.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from "react"; -import Router from "next/router"; import Image from "next/image"; import useSWR, { mutate } from "swr"; @@ -32,7 +31,7 @@ import { CURRENT_USER, USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys"; const Onboarding: NextPage = () => { const [step, setStep] = useState(null); - const { theme } = useTheme(); + const { theme, setTheme } = useTheme(); const { user, isLoading: userLoading } = useUserAuth("onboarding"); @@ -117,6 +116,10 @@ const Onboarding: NextPage = () => { await userService.updateUserOnBoard({ userRole: user.role }, user); }; + useEffect(() => { + setTheme("system"); + }, [setTheme]); + useEffect(() => { const handleStepChange = async () => { if (!user || !invitations) return; diff --git a/apps/app/pages/reset-password.tsx b/apps/app/pages/reset-password.tsx index c25974cb941..fa17d2333e2 100644 --- a/apps/app/pages/reset-password.tsx +++ b/apps/app/pages/reset-password.tsx @@ -3,6 +3,8 @@ import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; import Image from "next/image"; +// next-themes +import { useTheme } from "next-themes"; // react-hook-form import { useForm } from "react-hook-form"; // hooks @@ -31,6 +33,8 @@ const ResetPasswordPage: NextPage = () => { const { setToastAlert } = useToast(); + const { setTheme } = useTheme(); + const { register, handleSubmit, @@ -76,6 +80,10 @@ const ResetPasswordPage: NextPage = () => { ); }; + useEffect(() => { + setTheme("system"); + }, [setTheme]); + useEffect(() => { if (parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0")) router.push("/"); else setIsLoading(false); diff --git a/apps/app/pages/sign-up.tsx b/apps/app/pages/sign-up.tsx index fe8960d7362..72a391ea460 100644 --- a/apps/app/pages/sign-up.tsx +++ b/apps/app/pages/sign-up.tsx @@ -3,6 +3,8 @@ import React, { useEffect, useState } from "react"; import Image from "next/image"; import { useRouter } from "next/router"; +// next-themes +import { useTheme } from "next-themes"; // services import authenticationService from "services/authentication.service"; // hooks @@ -31,6 +33,8 @@ const SignUp: NextPage = () => { const { setToastAlert } = useToast(); + const { setTheme } = useTheme(); + const { mutateUser } = useUserAuth("sign-in"); const handleSignUp = async (formData: EmailPasswordFormValues) => { @@ -62,6 +66,10 @@ const SignUp: NextPage = () => { ); }; + useEffect(() => { + setTheme("system"); + }, [setTheme]); + useEffect(() => { if (parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0")) router.push("/"); else setIsLoading(false); diff --git a/apps/app/services/authentication.service.ts b/apps/app/services/authentication.service.ts index 86f55e32989..e4a33bff8a0 100644 --- a/apps/app/services/authentication.service.ts +++ b/apps/app/services/authentication.service.ts @@ -1,5 +1,6 @@ // services import APIService from "services/api.service"; +import { ICurrentUserResponse } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -32,7 +33,11 @@ class AuthService extends APIService { }); } - async socialAuth(data: any) { + async socialAuth(data: any): Promise<{ + access_token: string; + refresh_toke: string; + user: ICurrentUserResponse; + }> { return this.post("/api/social-auth/", data, { headers: {} }) .then((response) => { this.setAccessToken(response?.data?.access_token); diff --git a/apps/app/types/users.d.ts b/apps/app/types/users.d.ts index 3151345e098..ec77df2429d 100644 --- a/apps/app/types/users.d.ts +++ b/apps/app/types/users.d.ts @@ -46,6 +46,7 @@ export interface ICustomTheme { sidebarText: string; darkPalette: boolean; palette: string; + theme: string; } export interface ICurrentUserResponse extends IUser {