chore: use client side for layout and page

This commit is contained in:
Aaryan Khandelwal 2024-06-04 20:11:03 +05:30
parent 4c5c8a7483
commit a0de1daea2
14 changed files with 81 additions and 182 deletions

View File

@ -32,12 +32,15 @@ const ProjectIssuesPage = (props: Props) => {
publishService publishService
.fetchAnchorFromProjectDetails(workspaceSlug, projectId) .fetchAnchorFromProjectDetails(workspaceSlug, projectId)
.then((res) => { .then((res) => {
let url = `/issues/${res.anchor}`; let url = "";
const params = new URLSearchParams(); if (res.entity_name === "project") {
if (board) params.append("board", board); url = `/issues/${res.anchor}`;
if (peekId) params.append("peekId", peekId); const params = new URLSearchParams();
if (params.toString()) url += `?${params.toString()}`; if (board) params.append("board", board);
navigate(url); if (peekId) params.append("peekId", peekId);
if (params.toString()) url += `?${params.toString()}`;
navigate(url);
} else throw Error("Invalid entity name");
}) })
.catch(() => setError(true)); .catch(() => setError(true));
}, [board, peekId, projectId, workspaceSlug]); }, [board, peekId, projectId, workspaceSlug]);

View File

@ -1,23 +1,34 @@
"use client";
import { observer } from "mobx-react-lite";
import Image from "next/image"; import Image from "next/image";
import { notFound } from "next/navigation"; import useSWR from "swr";
// components // components
import { LogoSpinner } from "@/components/common";
import IssueNavbar from "@/components/issues/navbar"; import IssueNavbar from "@/components/issues/navbar";
// hooks // hooks
import { usePublish } from "@/hooks/store"; import { usePublish, usePublishList } from "@/hooks/store";
// assets // assets
import planeLogo from "@/public/plane-logo.svg"; import planeLogo from "@/public/plane-logo.svg";
type Props = { children: React.ReactNode; params: { anchor: string } }; type Props = {
children: React.ReactNode;
params: {
anchor: string;
};
};
const ProjectIssuesLayout = (props: Props) => { const ProjectIssuesLayout = observer((props: Props) => {
const { children, params } = props; const { children, params } = props;
// params // params
const { anchor } = params; const { anchor } = params;
// store hooks // store hooks
const { fetchPublishSettings } = usePublishList();
const publishSettings = usePublish(anchor); const publishSettings = usePublish(anchor);
const { id, workspace_detail, project } = publishSettings; // fetch publish settings
useSWR(anchor ? `PUBLISH_SETTINGS_${anchor}` : null, anchor ? () => fetchPublishSettings(anchor) : null);
if (!workspace_detail || !project || !id) notFound(); if (!publishSettings) return <LogoSpinner />;
return ( return (
<div className="relative flex h-screen min-h-[500px] w-screen flex-col overflow-hidden"> <div className="relative flex h-screen min-h-[500px] w-screen flex-col overflow-hidden">
@ -40,6 +51,6 @@ const ProjectIssuesLayout = (props: Props) => {
</a> </a>
</div> </div>
); );
}; });
export default ProjectIssuesLayout; export default ProjectIssuesLayout;

View File

@ -1,11 +1,10 @@
"use client"; "use client";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import useSWR from "swr";
// components // components
import { ProjectDetailsView } from "@/components/views"; import { ProjectDetailsView } from "@/components/views";
// hooks // hooks
import { usePublish, usePublishList } from "@/hooks/store"; import { usePublish } from "@/hooks/store";
type Props = { type Props = {
params: { params: {
@ -19,11 +18,8 @@ const ProjectIssuesPage = (props: Props) => {
// params // params
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const peekId = searchParams.get("peekId") || undefined; const peekId = searchParams.get("peekId") || undefined;
// store hooks
const { fetchPublishSettings } = usePublishList();
const publishSettings = usePublish(anchor);
useSWR(anchor ? `PUBLISH_SETTINGS_${anchor}` : null, anchor ? () => fetchPublishSettings(anchor) : null); const publishSettings = usePublish(anchor);
if (!publishSettings) return null; if (!publishSettings) return null;

View File

@ -1,49 +0,0 @@
import Image from "next/image";
import { notFound } from "next/navigation";
import useSWR from "swr";
// components
import IssueNavbar from "@/components/issues/navbar";
// hooks
import { usePublish, usePublishList } from "@/hooks/store";
// assets
import planeLogo from "@/public/plane-logo.svg";
type Props = { children: React.ReactNode; params: { anchor: string } };
const PageDetailsLayout = (props: Props) => {
const { children, params } = props;
// params
const { anchor } = params;
// store hooks
const { fetchPublishSettings } = usePublishList();
const publishSettings = usePublish(anchor);
const { id, workspace_detail, project } = publishSettings;
useSWR(anchor ? `PUBLISH_SETTINGS_${anchor}` : null, anchor ? () => fetchPublishSettings(anchor) : null);
if (!workspace_detail || !project || !id) notFound();
return (
<div className="relative flex h-screen min-h-[500px] w-screen flex-col overflow-hidden">
<div className="relative flex h-[60px] flex-shrink-0 select-none items-center border-b border-custom-border-300 bg-custom-sidebar-background-100">
<IssueNavbar publishSettings={publishSettings} />
</div>
<div className="relative h-full w-full overflow-hidden bg-custom-background-90">{children}</div>
<a
href="https://plane.so"
className="fixed bottom-2.5 right-5 !z-[999999] flex items-center gap-1 rounded border border-custom-border-200 bg-custom-background-100 px-2 py-1 shadow-custom-shadow-2xs"
target="_blank"
rel="noreferrer noopener"
>
<div className="relative grid h-6 w-6 place-items-center">
<Image src={planeLogo} alt="Plane logo" className="h-6 w-6" height="24" width="24" />
</div>
<div className="text-xs">
Powered by <span className="font-semibold">Plane Deploy</span>
</div>
</a>
</div>
);
};
export default PageDetailsLayout;

View File

@ -1,27 +0,0 @@
"use client";
import useSWR from "swr";
// hooks
import { usePublish, usePublishList } from "@/hooks/store";
type Props = {
params: {
anchor: string;
};
};
const PageDetailsPage = (props: Props) => {
const { params } = props;
const { anchor } = params;
// store hooks
const { fetchPublishSettings } = usePublishList();
const publishSettings = usePublish(anchor);
useSWR(anchor ? `PUBLISH_SETTINGS_${anchor}` : null, anchor ? () => fetchPublishSettings(anchor) : null);
if (!publishSettings) return null;
return <>Page details</>;
};
export default PageDetailsPage;

View File

@ -38,7 +38,7 @@ export const NavbarControls: FC<NavbarControlsProps> = observer((props) => {
const { getIssueFilters, isIssueFiltersUpdated, initIssueFilters } = useIssueFilter(); const { getIssueFilters, isIssueFiltersUpdated, initIssueFilters } = useIssueFilter();
const { setPeekId } = useIssueDetails(); const { setPeekId } = useIssueDetails();
// derived values // derived values
const { anchor, views, workspace_detail } = publishSettings; const { anchor, view_props, workspace_detail } = publishSettings;
const issueFilters = anchor ? getIssueFilters(anchor) : undefined; const issueFilters = anchor ? getIssueFilters(anchor) : undefined;
const activeLayout = issueFilters?.display_filters?.layout || undefined; const activeLayout = issueFilters?.display_filters?.layout || undefined;
@ -49,11 +49,11 @@ export const NavbarControls: FC<NavbarControlsProps> = observer((props) => {
const viewsAcceptable: string[] = []; const viewsAcceptable: string[] = [];
let currentBoard: TIssueLayout | null = null; let currentBoard: TIssueLayout | null = null;
if (views?.list) viewsAcceptable.push("list"); if (view_props?.list) viewsAcceptable.push("list");
if (views?.kanban) viewsAcceptable.push("kanban"); if (view_props?.kanban) viewsAcceptable.push("kanban");
if (views?.calendar) viewsAcceptable.push("calendar"); if (view_props?.calendar) viewsAcceptable.push("calendar");
if (views?.gantt) viewsAcceptable.push("gantt"); if (view_props?.gantt) viewsAcceptable.push("gantt");
if (views?.spreadsheet) viewsAcceptable.push("spreadsheet"); if (view_props?.spreadsheet) viewsAcceptable.push("spreadsheet");
if (board) { if (board) {
if (viewsAcceptable.includes(board.toString())) currentBoard = board.toString() as TIssueLayout; if (viewsAcceptable.includes(board.toString())) currentBoard = board.toString() as TIssueLayout;
@ -95,7 +95,7 @@ export const NavbarControls: FC<NavbarControlsProps> = observer((props) => {
initIssueFilters, initIssueFilters,
setPeekId, setPeekId,
isIssueFiltersUpdated, isIssueFiltersUpdated,
views, view_props,
workspace_detail, workspace_detail,
]); ]);

View File

@ -10,19 +10,14 @@ class PublishService extends APIService {
} }
async fetchPublishSettings(anchor: string): Promise<TPublishSettings> { async fetchPublishSettings(anchor: string): Promise<TPublishSettings> {
return this.get(`/api/public/publish-settings/${anchor}/`) return this.get(`/api/public/anchor/${anchor}/settings/`)
.then((response) => response?.data) .then((response) => response?.data)
.catch((error) => { .catch((error) => {
throw error?.response; throw error?.response;
}); });
} }
async fetchAnchorFromProjectDetails( async fetchAnchorFromProjectDetails(workspaceSlug: string, projectID: string): Promise<TPublishSettings> {
workspaceSlug: string,
projectID: string
): Promise<{
anchor: string;
}> {
return this.get(`/api/public/workspaces/${workspaceSlug}/projects/${projectID}/anchor/`) return this.get(`/api/public/workspaces/${workspaceSlug}/projects/${projectID}/anchor/`)
.then((response) => response?.data) .then((response) => response?.data)
.catch((error) => { .catch((error) => {

View File

@ -3,7 +3,7 @@ import { observable, makeObservable, computed } from "mobx";
import { RootStore } from "@/store/root.store"; import { RootStore } from "@/store/root.store";
// types // types
import { TProjectDetails, TViewDetails, TWorkspaceDetails } from "@/types/project"; import { TProjectDetails, TViewDetails, TWorkspaceDetails } from "@/types/project";
import { TPublishSettings } from "@/types/publish"; import { TPublishEntityType, TPublishSettings } from "@/types/publish";
export interface IPublishStore extends TPublishSettings { export interface IPublishStore extends TPublishSettings {
// computed // computed
@ -19,6 +19,8 @@ export class PublishStore implements IPublishStore {
comments: boolean; comments: boolean;
created_at: string | undefined; created_at: string | undefined;
created_by: string | undefined; created_by: string | undefined;
entity_identifier: string | undefined;
entity_name: TPublishEntityType | undefined;
id: string | undefined; id: string | undefined;
inbox: unknown; inbox: unknown;
project: string | undefined; project: string | undefined;
@ -26,7 +28,7 @@ export class PublishStore implements IPublishStore {
reactions: boolean; reactions: boolean;
updated_at: string | undefined; updated_at: string | undefined;
updated_by: string | undefined; updated_by: string | undefined;
views: TViewDetails | undefined; view_props: TViewDetails | undefined;
votes: boolean; votes: boolean;
workspace: string | undefined; workspace: string | undefined;
workspace_detail: TWorkspaceDetails | undefined; workspace_detail: TWorkspaceDetails | undefined;
@ -39,6 +41,8 @@ export class PublishStore implements IPublishStore {
this.comments = publishSettings.comments; this.comments = publishSettings.comments;
this.created_at = publishSettings.created_at; this.created_at = publishSettings.created_at;
this.created_by = publishSettings.created_by; this.created_by = publishSettings.created_by;
this.entity_identifier = publishSettings.entity_identifier;
this.entity_name = publishSettings.entity_name;
this.id = publishSettings.id; this.id = publishSettings.id;
this.inbox = publishSettings.inbox; this.inbox = publishSettings.inbox;
this.project = publishSettings.project; this.project = publishSettings.project;
@ -46,7 +50,7 @@ export class PublishStore implements IPublishStore {
this.reactions = publishSettings.reactions; this.reactions = publishSettings.reactions;
this.updated_at = publishSettings.updated_at; this.updated_at = publishSettings.updated_at;
this.updated_by = publishSettings.updated_by; this.updated_by = publishSettings.updated_by;
this.views = publishSettings.views; this.view_props = publishSettings.view_props;
this.votes = publishSettings.votes; this.votes = publishSettings.votes;
this.workspace = publishSettings.workspace; this.workspace = publishSettings.workspace;
this.workspace_detail = publishSettings.workspace_detail; this.workspace_detail = publishSettings.workspace_detail;
@ -57,6 +61,8 @@ export class PublishStore implements IPublishStore {
comments: observable.ref, comments: observable.ref,
created_at: observable.ref, created_at: observable.ref,
created_by: observable.ref, created_by: observable.ref,
entity_identifier: observable.ref,
entity_name: observable.ref,
id: observable.ref, id: observable.ref,
inbox: observable, inbox: observable,
project: observable.ref, project: observable.ref,
@ -64,7 +70,7 @@ export class PublishStore implements IPublishStore {
reactions: observable.ref, reactions: observable.ref,
updated_at: observable.ref, updated_at: observable.ref,
updated_by: observable.ref, updated_by: observable.ref,
views: observable, view_props: observable,
votes: observable.ref, votes: observable.ref,
workspace: observable.ref, workspace: observable.ref,
workspace_detail: observable, workspace_detail: observable,

View File

@ -22,21 +22,3 @@ export type TProjectDetails = {
logo_props: TLogoProps; logo_props: TLogoProps;
description: string; description: string;
}; };
export type TProjectSettings = {
id: string;
anchor: string;
comments: boolean;
reactions: boolean;
votes: 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;
};

View File

@ -1,10 +1,14 @@
import { TProjectDetails, TViewDetails, TWorkspaceDetails } from "./project"; import { TProjectDetails, TViewDetails, TWorkspaceDetails } from "./project";
export type TPublishEntityType = "project";
export type TPublishSettings = { export type TPublishSettings = {
anchor: string | undefined; anchor: string | undefined;
comments: boolean; comments: boolean;
created_at: string | undefined; created_at: string | undefined;
created_by: string | undefined; created_by: string | undefined;
entity_identifier: string | undefined;
entity_name: TPublishEntityType | undefined;
id: string | undefined; id: string | undefined;
inbox: unknown; inbox: unknown;
project: string | undefined; project: string | undefined;
@ -12,7 +16,7 @@ export type TPublishSettings = {
reactions: boolean; reactions: boolean;
updated_at: string | undefined; updated_at: string | undefined;
updated_by: string | undefined; updated_by: string | undefined;
views: TViewDetails | undefined; view_props: TViewDetails | undefined;
votes: boolean; votes: boolean;
workspace: string | undefined; workspace: string | undefined;
workspace_detail: TWorkspaceDetails | undefined; workspace_detail: TWorkspaceDetails | undefined;

View File

@ -311,11 +311,9 @@ export const PublishProjectModal: React.FC<Props> = observer((props) => {
{project.is_deployed && ( {project.is_deployed && (
<> <>
<div className="relative flex items-center gap-2 rounded-md border border-custom-border-100 bg-custom-background-80 px-3 py-2"> <div className="relative flex items-center gap-2 rounded-md border border-custom-border-100 bg-custom-background-80 px-3 py-2">
<div className="flex-grow truncate text-sm"> <div className="flex-grow truncate text-sm">{`${SPACE_URL}/issues/`}</div>
{`${SPACE_URL}/${workspaceSlug}/${project.id}`}
</div>
<div className="relative flex flex-shrink-0 items-center gap-1"> <div className="relative flex flex-shrink-0 items-center gap-1">
<CopyLinkToClipboard copy_link={`${SPACE_URL}/${workspaceSlug}/${project.id}`} /> <CopyLinkToClipboard copy_link={`${SPACE_URL}/issues`} />
</div> </div>
</div> </div>
<div className="mt-3 flex items-center gap-1 text-custom-primary-100"> <div className="mt-3 flex items-center gap-1 text-custom-primary-100">

View File

@ -9,8 +9,8 @@ export class ProjectPublishService extends APIService {
super(API_BASE_URL); super(API_BASE_URL);
} }
async getProjectSettingsAsync(workspace_slug: string, project_slug: string): Promise<any> { async getProjectSettingsAsync(workspaceSlug: string, projectID: string): Promise<IProjectPublishSettings> {
return this.get(`/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/`) return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/`)
.then((response) => response?.data) .then((response) => response?.data)
.catch((error) => { .catch((error) => {
throw error?.response; throw error?.response;
@ -18,11 +18,11 @@ export class ProjectPublishService extends APIService {
} }
async createProjectSettingsAsync( async createProjectSettingsAsync(
workspace_slug: string, workspaceSlug: string,
project_slug: string, projectID: string,
data: IProjectPublishSettings data: IProjectPublishSettings
): Promise<any> { ): Promise<IProjectPublishSettings> {
return this.post(`/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/`, data)
.then((response) => response?.data) .then((response) => response?.data)
.catch((error) => { .catch((error) => {
throw error?.response; throw error?.response;
@ -30,13 +30,13 @@ export class ProjectPublishService extends APIService {
} }
async updateProjectSettingsAsync( async updateProjectSettingsAsync(
workspace_slug: string, workspaceSlug: string,
project_slug: string, projectID: string,
project_publish_id: string, project_publish_id: string,
data: IProjectPublishSettings data: IProjectPublishSettings
): Promise<any> { ): Promise<any> {
return this.patch( return this.patch(
`/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/${project_publish_id}/`, `/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/${project_publish_id}/`,
data data
) )
.then((response) => response?.data) .then((response) => response?.data)
@ -45,13 +45,9 @@ export class ProjectPublishService extends APIService {
}); });
} }
async deleteProjectSettingsAsync( async deleteProjectSettingsAsync(workspaceSlug: string, projectID: string, project_publish_id: string): Promise<any> {
workspace_slug: string,
project_slug: string,
project_publish_id: string
): Promise<any> {
return this.delete( return this.delete(
`/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/${project_publish_id}/` `/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/${project_publish_id}/`
) )
.then((response) => response?.data) .then((response) => response?.data)
.catch((error) => { .catch((error) => {

View File

@ -28,7 +28,7 @@ export interface IProjectPublishStore {
// observables // observables
projectPublishSettings: IProjectPublishSettings | "not-initialized"; projectPublishSettings: IProjectPublishSettings | "not-initialized";
// project settings actions // project settings actions
getProjectSettingsAsync: (workspaceSlug: string, projectId: string) => Promise<void>; getProjectSettingsAsync: (workspaceSlug: string, projectId: string) => Promise<IProjectPublishSettings>;
updateProjectSettingsAsync: ( updateProjectSettingsAsync: (
workspaceSlug: string, workspaceSlug: string,
projectId: string, projectId: string,
@ -36,7 +36,11 @@ export interface IProjectPublishStore {
data: IProjectPublishSettings data: IProjectPublishSettings
) => Promise<void>; ) => Promise<void>;
// project publish actions // project publish actions
publishProject: (workspaceSlug: string, projectId: string, data: IProjectPublishSettings) => Promise<void>; publishProject: (
workspaceSlug: string,
projectId: string,
data: IProjectPublishSettings
) => Promise<IProjectPublishSettings>;
unPublishProject: (workspaceSlug: string, projectId: string, projectPublishId: string) => Promise<void>; unPublishProject: (workspaceSlug: string, projectId: string, projectPublishId: string) => Promise<void>;
} }
@ -85,24 +89,9 @@ export class ProjectPublishStore implements IProjectPublishStore {
this.fetchSettingsLoader = true; this.fetchSettingsLoader = true;
}); });
const response = await this.projectPublishService.getProjectSettingsAsync(workspaceSlug, projectId); const response = await this.projectPublishService.getProjectSettingsAsync(workspaceSlug, projectId);
if (response && response.length > 0) { if (response) {
const _projectPublishSettings: IProjectPublishSettings = {
id: response[0]?.id,
comments: response[0]?.comments,
reactions: response[0]?.reactions,
votes: response[0]?.votes,
views: {
list: response[0]?.views?.list || false,
kanban: response[0]?.views?.kanban || false,
calendar: response[0]?.views?.calendar || false,
gantt: response[0]?.views?.gantt || false,
spreadsheet: response[0]?.views?.spreadsheet || false,
},
inbox: response[0]?.inbox || null,
project: response[0]?.project || null,
};
runInAction(() => { runInAction(() => {
this.projectPublishSettings = _projectPublishSettings; this.projectPublishSettings = response;
this.fetchSettingsLoader = false; this.fetchSettingsLoader = false;
}); });
} else { } else {
@ -134,23 +123,13 @@ export class ProjectPublishStore implements IProjectPublishStore {
}); });
const response = await this.projectPublishService.createProjectSettingsAsync(workspaceSlug, projectId, data); const response = await this.projectPublishService.createProjectSettingsAsync(workspaceSlug, projectId, data);
if (response) { if (response) {
const _projectPublishSettings: IProjectPublishSettings = {
id: response?.id || null,
comments: response?.comments || false,
reactions: response?.reactions || false,
votes: response?.votes || false,
views: { ...response?.views },
inbox: response?.inbox || null,
project: response?.project || null,
};
runInAction(() => { runInAction(() => {
this.projectPublishSettings = _projectPublishSettings; this.projectPublishSettings = response;
set(this.projectRootStore.project.projectMap, [projectId, "is_deployed"], true); set(this.projectRootStore.project.projectMap, [projectId, "is_deployed"], true);
this.generalLoader = false; this.generalLoader = false;
}); });
return response;
} }
return response;
} catch (error) { } catch (error) {
runInAction(() => { runInAction(() => {
this.generalLoader = false; this.generalLoader = false;

View File

@ -9437,6 +9437,11 @@ lucide-react@^0.378.0:
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.378.0.tgz#232acb99c6baedfa90959a2c0dd11327b058bde8" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.378.0.tgz#232acb99c6baedfa90959a2c0dd11327b058bde8"
integrity sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g== integrity sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==
lucide-react@^0.379.0:
version "0.379.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.379.0.tgz#29e34eeffae7fb241b64b09868cbe3ab888ef7cc"
integrity sha512-KcdeVPqmhRldldAAgptb8FjIunM2x2Zy26ZBh1RsEUcdLIvsEmbcw7KpzFYUy5BbpGeWhPu9Z9J5YXfStiXwhg==
lz-string@^1.5.0: lz-string@^1.5.0:
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941"