diff --git a/space/components/issues/navbar/controls.tsx b/space/components/issues/navbar/controls.tsx index a0d8bbbb4..888d85648 100644 --- a/space/components/issues/navbar/controls.tsx +++ b/space/components/issues/navbar/controls.tsx @@ -118,7 +118,9 @@ export const NavbarControls: FC = observer((props) => { {user?.id ? (
-
{user.display_name}
+
+ {user?.display_name || `${user?.first_name} ${user?.first_name}` || user?.email || "User"} +
) : (
diff --git a/space/components/views/project-details.tsx b/space/components/views/project-details.tsx index c26190589..462c656f0 100644 --- a/space/components/views/project-details.tsx +++ b/space/components/views/project-details.tsx @@ -36,8 +36,7 @@ export const ProjectDetailsView: FC = observer((props) // hooks const { fetchProjectSettings } = useProject(); const { issueFilters } = useIssueFilter(); - const { loader, issues, error } = useIssue(); - const { fetchPublicIssues } = useIssue(); + const { loader, issues, error, fetchPublicIssues } = useIssue(); const issueDetailStore = useIssueDetails(); const { data: currentUser, fetchCurrentUser } = useUser(); @@ -51,12 +50,10 @@ export const ProjectDetailsView: FC = observer((props) ? () => fetchPublicIssues(workspaceSlug, projectId, { states, priority, labels }) : null ); - - useEffect(() => { - if (!currentUser) { - fetchCurrentUser(); - } - }, [currentUser, fetchCurrentUser]); + useSWR( + workspaceSlug && projectId && !currentUser ? "WORKSPACE_PROJECT_CURRENT_USER" : null, + workspaceSlug && projectId && !currentUser ? () => fetchCurrentUser() : null + ); useEffect(() => { if (peekId && workspaceSlug && projectId) { diff --git a/space/store/project.store.ts b/space/store/project.store.ts index 70a9c1043..02f250323 100644 --- a/space/store/project.store.ts +++ b/space/store/project.store.ts @@ -1,19 +1,19 @@ // mobx -import { observable, action, makeObservable, runInAction } from "mobx"; +import { observable, action, makeObservable, runInAction, computed } from "mobx"; // service import ProjectService from "@/services/project.service"; // store types import { RootStore } from "@/store/root.store"; // types -import { IWorkspace, IProject, IProjectSettings } from "@/types/project"; +import { TWorkspaceDetails, TProjectDetails, TProjectSettings } from "@/types/project"; export interface IProjectStore { // observables loader: boolean; - error: any | null; - workspace: IWorkspace | null; - project: IProject | null; - settings: IProjectSettings | null; + error: any | undefined; + settings: TProjectSettings | undefined; + workspace: TWorkspaceDetails | undefined; + project: TProjectDetails | undefined; canReact: boolean; canComment: boolean; canVote: boolean; @@ -25,13 +25,10 @@ export interface IProjectStore { export class ProjectStore implements IProjectStore { // observables loader: boolean = false; - error: any | null = null; - workspace: IWorkspace | null = null; - project: IProject | null = null; - settings: IProjectSettings | null = null; - canReact: boolean = false; - canComment: boolean = false; - canVote: boolean = false; + error: any | undefined = undefined; + settings: TProjectSettings | undefined = undefined; + workspace: TWorkspaceDetails | undefined = undefined; + project: TProjectDetails | undefined = undefined; // service projectService; @@ -44,28 +41,28 @@ export class ProjectStore implements IProjectStore { workspace: observable, project: observable, settings: observable, - canReact: observable.ref, - canComment: observable.ref, - canVote: observable.ref, + // computed + canReact: computed, + canComment: computed, + canVote: computed, // actions fetchProjectSettings: action, - hydrate: action, - // computed }); - // services this.projectService = new ProjectService(); } - hydrate = (projectSettings: any) => { - const { workspace_detail, project_details, votes, comments, reactions } = projectSettings; - this.workspace = workspace_detail; - this.project = project_details; - this.canComment = comments; - this.canVote = votes; - this.canReact = reactions; - }; + // computed + get canReact() { + return this.settings?.reactions ?? false; + } + get canComment() { + return this.settings?.comments ?? false; + } + get canVote() { + return this.settings?.votes ?? false; + } fetchProjectSettings = async (workspace_slug: string, project_slug: string) => { try { @@ -75,14 +72,11 @@ export class ProjectStore implements IProjectStore { const response = await this.projectService.getProjectSettings(workspace_slug, project_slug); if (response) { - const currentProject: IProject = { ...response?.project_details }; - const currentWorkspace: IWorkspace = { ...response?.workspace_detail }; - const currentDeploySettings = { ...response }; this.store.issueFilter.updateLayoutOptions(response?.views); runInAction(() => { - this.project = currentProject; - this.workspace = currentWorkspace; - this.settings = currentDeploySettings; + this.project = response?.project_details; + this.workspace = response?.workspace_detail; + this.settings = response; this.loader = false; }); } @@ -93,4 +87,10 @@ export class ProjectStore implements IProjectStore { return error; } }; + + hydrate = (projectSettings: TProjectSettings) => { + const { workspace_detail, project_details } = projectSettings; + this.workspace = workspace_detail; + this.project = project_details; + }; } diff --git a/space/store/root.store.ts b/space/store/root.store.ts index a11e0d910..4a31840db 100644 --- a/space/store/root.store.ts +++ b/space/store/root.store.ts @@ -32,8 +32,8 @@ export class RootStore { // eslint-disable-next-line @typescript-eslint/no-explicit-any hydrate = (data: any) => { if (!data) return; - this.instance.hydrate(data?.instance || {}); - this.user.hydrate(data?.user || {}); + this.instance.hydrate(data?.instance || undefined); + this.user.hydrate(data?.user || undefined); }; reset = () => { diff --git a/space/store/user.store.ts b/space/store/user.store.ts index 37ce30732..5e65a59fb 100644 --- a/space/store/user.store.ts +++ b/space/store/user.store.ts @@ -29,7 +29,7 @@ export interface IUserStore { // actions fetchCurrentUser: () => Promise; updateCurrentUser: (data: Partial) => Promise; - hydrate: (data: IUser) => void; + hydrate: (data: IUser | undefined) => void; reset: () => void; signOut: () => Promise; } @@ -91,7 +91,7 @@ export class UserStore implements IUserStore { fetchCurrentUser = async (): Promise => { try { runInAction(() => { - this.isLoading = true; + if (this.data === undefined) this.isLoading = true; this.error = undefined; }); const user = await this.userService.currentUser(); @@ -155,7 +155,8 @@ export class UserStore implements IUserStore { } }; - hydrate = (data: IUser): void => { + hydrate = (data: IUser | undefined): void => { + if (!data) return; this.data = { ...this.data, ...data }; }; diff --git a/space/styles/globals.css b/space/styles/globals.css index b7d551c0e..47804b768 100644 --- a/space/styles/globals.css +++ b/space/styles/globals.css @@ -329,3 +329,11 @@ height: 0 !important; width: 0 !important; } + +/* By applying below class, the autofilled text in form fields will not have the default autofill background color and styles applied by WebKit browsers */ +.disable-autofill-style:-webkit-autofill, +.disable-autofill-style:-webkit-autofill:hover, +.disable-autofill-style:-webkit-autofill:focus, +.disable-autofill-style:-webkit-autofill:active { + -webkit-background-clip: text; +} diff --git a/space/types/project.d.ts b/space/types/project.d.ts index 7e81d366c..99dbfec8b 100644 --- a/space/types/project.d.ts +++ b/space/types/project.d.ts @@ -1,29 +1,42 @@ import { TProjectLogoProps } from "@plane/types"; -export interface IWorkspace { - id: string; +export type TWorkspaceDetails = { name: string; slug: string; -} + id: string; +}; -export interface IProject { +export type TViewDetails = { + list: boolean; + gantt: boolean; + kanban: boolean; + calendar: boolean; + spreadsheet: boolean; +}; + +export type TProjectDetails = { id: string; identifier: string; name: string; - description: string; - cover_image: string | null; + cover_image: string | undefined; logo_props: TProjectLogoProps; -} + description: string; +}; -export interface IProjectSettings { +export type TProjectSettings = { + id: string; + anchor: string; comments: boolean; reactions: boolean; votes: boolean; - views: { - list: boolean; - gantt: boolean; - kanban: boolean; - calendar: boolean; - spreadsheet: boolean; - }; -} + inbox: unknown; + workspace: string; + workspace_detail: TWorkspaceDetails; + project: string; + project_details: TProjectDetails; + views: TViewDetails; + created_by: string; + updated_by: string; + created_at: string; + updated_at: string; +}; diff --git a/web/styles/globals.css b/web/styles/globals.css index 8ca8351ad..482f056c6 100644 --- a/web/styles/globals.css +++ b/web/styles/globals.css @@ -668,7 +668,6 @@ div.web-view-spinner div.bar12 { } /* By applying below class, the autofilled text in form fields will not have the default autofill background color and styles applied by WebKit browsers */ - .disable-autofill-style:-webkit-autofill, .disable-autofill-style:-webkit-autofill:hover, .disable-autofill-style:-webkit-autofill:focus,