feat: app dir migration (#4743)

* feat: creating new app dir structure for web app

* fix: moving few pages to app dir

* fix: adding profile settings layout

* fix: errors on app dir.

* chore: remove pages routes.

* chore: add sign-in/ sign-up, invitations, onboarding pages.

* [WEB-1374] fix: clear changes made on modal close (#4555)

* [WEB-1480] fix: preserve page access when making a copy (#4568)

* [WEB-1465] fix: theme fluctuation on initial load. (#4638)

* [WEB-1445] fix: issue creation on sub groups when cycle/ module grouping is applied. (#4636)

* [WEB-1244] fix: add better image insertion and replacement logic in the editor (#4508)

* fix: add better image insertion and replacement logic

* refactor: image handling in editor

* chore: remove passing uploadKey around

* refactor: remove unused code

* fix: redundant files removed

* fix: add is editor ready to discard api to control behvaiours from our app

* fix: focus issues and image insertion position when not using slash command

* fix: import order fixed

* fix: notification mark all as read (#4643)

* chore: remove enter key extension (#4648)

* [WEB-1467] chore: run the API's required to bootstrap the application in parallel. (#4642)

* [WEB - 1482] fix: uploads when using block storages other than s3 and minio (#4647)

* fix: minio storage and redirection

* dev: disconnect web url and app base url configuration.

* fix: negate check while trying to discard (#4653)

* fix: email notification preferences (#4656)

* [WEB-1493] chore: product tour asset and app sidebar quick action hover (#4655)

* chore: product tour asset updated

* fix: app sidebar quick action hover

* fix: project state setting state name remove camel case logic (#4652)

* [WEB-1419] chore: enable module creation with dates older than today. (#4659)

* [WEB-1216] chore: increase module empty state for consistency. (#4658)

* fix: build errors

* [WEB-1235] chore: module and cycle sidebar graph improvement (#4650)

* chore: module and cycle sidebar graph improvement

* chore: code refactor

* [WEB-1424] chore: page and view logo implementation, and emoji/icon (#4662)

* [WEB-1424] chore: page and view logo implementation, and emoji/icon picker improvement (#4583)

* chore: added logo_props

* chore: logo props in cycles, views and modules

* chore: emoji icon picker types updated

* chore: info icon added to plane ui package

* chore: icon color adjust helper function added

* style: icon picker ui improvement and default color options updated

* chore: update page logo action added in store

* chore: emoji code to unicode helper function added

* chore: common logo renderer component added

* chore: app header project logo updated

* chore: project logo updated across platform

* chore: page logo picker added

* chore: control link component improvement

* chore: list item improvement

* chore: emoji picker component updated

* chore: space app and package logo prop type updated

* chore: migration

* chore: logo added to project view

* chore: page logo picker added in create modal and breadcrumbs

* chore: view logo picker added in create modal and updated breadcrumbs

* fix: build error

* chore: AIO docker images for preview deployments (#4605)

* fix: adding single docker base file

* action added

* fix action

* dockerfile.base modified

* action fix

* dockerfile

* fix: base aio dockerfile

* fix: dockerfile.base

* fix: dockerfile base

* fix: modified folder structure

* fix: action

* fix: dockerfile

* fix: dockerfile.base

* fix: supervisor file name changed

* fix: base dockerfile updated

* fix dockerfile base

* fix: base dockerfile

* fix: docker files

* fix: base dockerfile

* update base image

* modified docker aio base

* aio base modified to debian-12-slim

* fixes

* finalize the dockerfiles with volume exposure

* modified the aio build and dockerfile

* fix: codacy suggestions implemented

* fix: codacy fix

* update aio build action

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>

* fix: merge conflict

* chore: lucide react added to planu ui package

* chore: new emoji picker component added with lucid icon and code refactor

* chore: logo component updated

* chore: emoji picker updated for pages and views

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Manish Gupta <59428681+mguptahub@users.noreply.github.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>

* fix: build error

---------

Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Manish Gupta <59428681+mguptahub@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>

* refactor: drag handle component (#4663)

* refactor: checkbox ui component (#4665)

* [WEB-1325] chore: refactor inbox issue store to avoid data loss. (#4640)

* [WEB-1325] chore: refactor inbox issue store to avoid data loss.

* chore: inbox store improvement.

* chore: priority dropdown accepts undefined (#4666)

* chore: added buttonClassName prop to label dropdown (#4671)

* chore: created new constants for marketing website page links (#4670)

* chore: added a prop to render default state conditionally (#4669)

* [WEB-1501] dev: multiple select core components (#4667)

* dev: multiple select core components

* chore: added export statement

* chore: created a new constant for archivable state groups (#4668)

* chore: added primary variant to the alert modal (#4664)

* [WEB-1436] chore: pages improvement. (#4657)

* add empty state if no pages are available.
* set access to private in create page modal when the modal is open form private tab.

* [WEB-1440] chore: update cycle empty state to use project level access. (#4672)

* fix: checkbox ui component (#4675)

* fix: ai buttons overlapping issue (#4621)

* [WEB - 1500] chore: add extra fields on instance and create changelog table to store release change logs (#4673)

* chore: add extra fields on instance and create changelog table to store release change logs

* dev: rename new_version to latest_version

* [WEB - 1505] chore: alter instance id field (#4676)

* chore: instance id

* dev: update to max length

* feat: creating new app dir structure for web app

* fix: moving few pages to app dir

* feat: creating new app dir structure for web app

* fix: moving few pages to app dir

* fix: errors on app dir.

* chore: remove pages routes.

* chore: add sign-in/ sign-up, invitations, onboarding pages.

* fix: instance serializer

* fix: instance register script  (#4681)

* fix: instance register script

* dev: remove api key and add latest version and current version in types

* [WEB-1492] fix: resolved issue creation error in layouts while group_by and sub_group_by filters applied in quick add (#4682)

* fix: resolved issue creation error in layouts while group_by and sub_group_by filters applied in quick add

* fix: updated braces in conditions

* fix: inbox issue store update logic. (#4683)

* chore: update package version

* [WEB-1184] feat: issue bulk operations (#4674)

* feat: issue bulk operations

* style: bulk operations action bar

* chore: remove edition separation

* style: fix overlapping of response container in AI popover. (#4684)

* [WEB-1498] style: fix comments reaction alignment. (#4686)

* [WEB-1503] chore: add `autofocus` to name field in inline create/ update state component. (#4685)

* [WEB-1312] fix: trim file name before uploading (#4661)

* fix: trim file name before uploading

* fix: check the cursor position before inserting image

* dev: add trimming for file assets

* dev: add filename validation above if

* dev: make the validation to 50 to support user uploads

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>

* [WEB-1481] fix: multiple API calls in inbox issues on closed issues tab. (#4691)

* fix: multiple API calls on scroll and closed issues tab.

* fix: pagination loader on initial load.

* feat: Add components required for estimates (#4690)

* Add sortable, radio and typography components

* Remove stray css classes

* Prevent drag of items from other draggable

* Minor cleanup

* Update yarn.lock

* Remove radio input component as it was build on
headless ui v2.0.0 and now we are using v1.7.0

* Fix build errors

* Update dependencies in use memo.

* [WEB-1521] chore: add configuration to enable/disable sign-ups. (#4697)

* fix: regenerating lock file

* fix: docker image build errors

* fix: remove `setupInterceptors` to avoid circular dependency.

* chore: migrate all `accounts` related routes.

* chore: migrate all `profiles` related routes.

* chore: workspace invitation and onboarding migration / fixes.

* chore: installation provider migrations.

* regression: focus changing issue with the peek overview editor (#4700)

* [WEB-1459] chore: save users all / favorite project list collapse state into localstorage. (#4701)

* [WEB-1501] chore: update selected entity details on entities list change (#4702)

* chore: update selected entity detials on entities list change

* chore: addd selectionHelpers as a prop

* [WEB-1517] chore: remove drag handle from list drag block (#4698)

* remove drag handle from list drag block

* align list group header with list item

* rearrange chevron for list subissues and rearrange spaces

* adding default draggable property to control link

* remove unnecessary dependencies for useEffect

* fix: email validation  (#4707)

* fix: email validation on complete login or sign up functionality

* dev: add try catch block

* dev: split up code

* dev: empty return

* fix: cache invalidation on new members invite (#4699)

* fix: build test pull request running on non draft PRs (#4708)

* fix: cache invalidation on new members invite (#4699)

* fix: add version max length (#4713)

* chore: migrations for `routing` hooks.

* [WEB-1533] chore: fix alignment issues in List and Spreadsheet view (#4714)

* fix alignment issues in List and Spreadsheet view

* fix spreadsheet indentation

* chore: migration for workspace dashboard/ views/ analytics/ settings and active-cycles.

* chore: handle undefined identifier case

* fix: Overflowing loader in issue edit modal (#4720)

* [WEB-1529] chore: workspace sidebar updates. (#4710)

* fix: temporary fix exiting lines with slashes (#4725)

* [WEB-1537] fix: inline code block size fixed for headers, etc (#4709)

* fix: inline code block size fixed for headers, etc

* feat: persisting focus accurately post converting the code block into text

* fix: typo in error handling

* [WEB-1526] feat: add auto merge behaviour to task lists and fix infinite backspace case (#4703)

* feat: add auto merge behaviour to task lists

* fix: unhandled cases for taskItem and taskList

* fix: css task list such that toggling task list doesn't shift things

* fix: task list jumps around while trying create/delete things in between two task lists

* fix: remove filtering for generic transactions i.e. transactions with some meta data while tying to join things

* chore: migration for profile activity along with headers refactor.

* [WEB-1201] dev: dropdowns (#4721)

* chore: lodash package added

* chore: dropdown key down hook added

* dev: dropdown component

* chore: build error and code refactor

* chore: readme file updated

* chore: added disabled prop to multiple select components (#4724)

* chore: added disabled prop to mutliple select group hoc

* style: fix empty space

* fix: don't add  as a sub-issue if parent has been removed (#4731)

* fix: member list item custom menu placement (#4729)

* [WEB-1535] chore: project logo picker improvement (#4718)

* chore: emoji icon picker improvement

* chore: emoji icon picker improvement

* fix: resolved border flicker on issue title (#4727)

* chore: profile activity empty state added (#4732)

* [WEB-1481] fix: inbox issue list update after changing issue status. (#4715)

* style: fix ux copy style on project feature preview page. (#4734)

* chore: remove clear seleciton logic on escape key press (#4735)

* chore: migrations for projects and project issues.

* chore: issue and properties filter dropdown improvement (#4733)

* save all filters and properties for views (#4728)

* chore: migrations for issue details route.

* chore: migration for cycle routes.

* chore: migration for module routes.

* chore: migrations for project views routes.

* chore: migrations for project pages routes.

* chore: migration for project inbox routes.

* chore: migration for project settings routes.

* chore: migrations for draft issues routes.

* chore: migrations for project archives routes.

* chore: remove unused headers.

* temp: comment out auth constant and use-reload-confirmation code to avoid errors.

---------

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: rahulramesha <71900764+rahulramesha@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Manish Gupta <59428681+mguptahub@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
Co-authored-by: guru_sainath <gurusainath007@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
Co-authored-by: Henit Chobisa <chobisa.henit@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
This commit is contained in:
sriram veeraghanta 2024-06-10 12:37:38 +05:30 committed by GitHub
parent 59fdd611e4
commit 5d807db69e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
417 changed files with 5196 additions and 3918 deletions

View File

@ -1,5 +1,6 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import Link from "next/link"; // import Link from "next/link";
// import { EAuthenticationErrorCodes } from "@/helpers/authentication.helper";
export enum EPageTypes { export enum EPageTypes {
PUBLIC = "PUBLIC", PUBLIC = "PUBLIC",
@ -41,7 +42,7 @@ export enum EAuthErrorCodes {
// Password strength // Password strength
INVALID_PASSWORD = "5020", INVALID_PASSWORD = "5020",
// Sign Up // Sign Up
USER_ACCOUNT_DEACTIVATED = "5019", // USER_ACCOUNT_DEACTIVATED = "5019",
USER_ALREADY_EXIST = "5030", USER_ALREADY_EXIST = "5030",
AUTHENTICATION_FAILED_SIGN_UP = "5035", AUTHENTICATION_FAILED_SIGN_UP = "5035",
REQUIRED_EMAIL_PASSWORD_SIGN_UP = "5040", REQUIRED_EMAIL_PASSWORD_SIGN_UP = "5040",
@ -91,281 +92,281 @@ export type TAuthErrorInfo = {
message: ReactNode; message: ReactNode;
}; };
const errorCodeMessages: { // const errorCodeMessages: {
[key in EAuthErrorCodes]: { title: string; message: (email?: string | undefined) => ReactNode }; // [key in EAuthErrorCodes]: { title: string; message: (email?: string | undefined) => ReactNode };
} = { // } = {
// global // // global
[EAuthErrorCodes.INSTANCE_NOT_CONFIGURED]: { // [EAuthErrorCodes.INSTANCE_NOT_CONFIGURED]: {
title: `Instance not configured`, // title: `Instance not configured`,
message: () => `Instance not configured. Please contact your administrator.`, // message: () => `Instance not configured. Please contact your administrator.`,
}, // },
[EAuthErrorCodes.SIGNUP_DISABLED]: { // [EAuthErrorCodes.SIGNUP_DISABLED]: {
title: `Sign up disabled`, // title: `Sign up disabled`,
message: () => `Sign up disabled. Please contact your administrator.`, // message: () => `Sign up disabled. Please contact your administrator.`,
}, // },
[EAuthErrorCodes.INVALID_PASSWORD]: { // [EAuthErrorCodes.INVALID_PASSWORD]: {
title: `Invalid password`, // title: `Invalid password`,
message: () => `Invalid password. Please try again.`, // message: () => `Invalid password. Please try again.`,
}, // },
[EAuthErrorCodes.SMTP_NOT_CONFIGURED]: { // [EAuthErrorCodes.SMTP_NOT_CONFIGURED]: {
title: `SMTP not configured`, // title: `SMTP not configured`,
message: () => `SMTP not configured. Please contact your administrator.`, // message: () => `SMTP not configured. Please contact your administrator.`,
}, // },
// email check in both sign up and sign in // email check in both sign up and sign in
[EAuthErrorCodes.INVALID_EMAIL]: { // [EAuthErrorCodes.INVALID_EMAIL]: {
title: `Invalid email`, // title: `Invalid email`,
message: () => `Invalid email. Please try again.`, // message: () => `Invalid email. Please try again.`,
}, // },
[EAuthenticationErrorCodes.EMAIL_REQUIRED]: { // [EAuthenticationErrorCodes.EMAIL_REQUIRED]: {
title: `Email required`, // title: `Email required`,
message: () => `Email required. Please try again.`, // message: () => `Email required. Please try again.`,
}, // },
// sign up // // sign up
[EAuthenticationErrorCodes.USER_ALREADY_EXIST]: { // [EAuthenticationErrorCodes.USER_ALREADY_EXIST]: {
title: `User already exists`, // title: `User already exists`,
message: (email = undefined) => ( // message: (email = undefined) => (
<div> // <div>
Your account is already registered.&nbsp; // Your account is already registered.&nbsp;
<Link // <Link
className="underline underline-offset-4 font-medium hover:font-bold transition-all" // className="underline underline-offset-4 font-medium hover:font-bold transition-all"
href={`/sign-in${email ? `?email=${encodeURIComponent(email)}` : ``}`} // href={`/sign-in${email ? `?email=${encodeURIComponent(email)}` : ``}`}
> // >
Sign In // Sign In
</Link> // </Link>
&nbsp;now. // &nbsp;now.
</div> // </div>
), // ),
}, // },
[EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: { // [EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: {
title: `Email and password required`, // title: `Email and password required`,
message: () => `Email and password required. Please try again.`, // message: () => `Email and password required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP]: { // [EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP]: {
title: `Authentication failed`, // title: `Authentication failed`,
message: () => `Authentication failed. Please try again.`, // message: () => `Authentication failed. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_UP]: { // [EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_UP]: {
title: `Invalid email`, // title: `Invalid email`,
message: () => `Invalid email. Please try again.`, // message: () => `Invalid email. Please try again.`,
}, // },
[EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: { // [EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: {
title: `Email and code required`, // title: `Email and code required`,
message: () => `Email and code required. Please try again.`, // message: () => `Email and code required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP]: { // [EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP]: {
title: `Invalid email`, // title: `Invalid email`,
message: () => `Invalid email. Please try again.`, // message: () => `Invalid email. Please try again.`,
}, // },
// sign in // // sign in
[EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: { // [EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
title: `User account deactivated`, // title: `User account deactivated`,
message: () => <div>Your account is deactivated. Contact support@plane.so.</div>, // message: () => <div>Your account is deactivated. Contact support@plane.so.</div>,
}, // },
[EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: { // [EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: {
title: `User does not exist`, // title: `User does not exist`,
message: (email = undefined) => ( // message: (email = undefined) => (
<div> // <div>
No account found.&nbsp; // No account found.&nbsp;
<Link // <Link
className="underline underline-offset-4 font-medium hover:font-bold transition-all" // className="underline underline-offset-4 font-medium hover:font-bold transition-all"
href={`/${email ? `?email=${encodeURIComponent(email)}` : ``}`} // href={`/${email ? `?email=${encodeURIComponent(email)}` : ``}`}
> // >
Create one // Create one
</Link> // </Link>
&nbsp;to get started. // &nbsp;to get started.
</div> // </div>
), // ),
}, // },
[EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: { // [EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: {
title: `Email and password required`, // title: `Email and password required`,
message: () => `Email and password required. Please try again.`, // message: () => `Email and password required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN]: { // [EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN]: {
title: `Authentication failed`, // title: `Authentication failed`,
message: () => `Authentication failed. Please try again.`, // message: () => `Authentication failed. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_IN]: { // [EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_IN]: {
title: `Invalid email`, // title: `Invalid email`,
message: () => `Invalid email. Please try again.`, // message: () => `Invalid email. Please try again.`,
}, // },
[EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: { // [EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: {
title: `Email and code required`, // title: `Email and code required`,
message: () => `Email and code required. Please try again.`, // message: () => `Email and code required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN]: { // [EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN]: {
title: `Invalid email`, // title: `Invalid email`,
message: () => `Invalid email. Please try again.`, // message: () => `Invalid email. Please try again.`,
}, // },
// Both Sign in and Sign up // // Both Sign in and Sign up
[EAuthenticationErrorCodes.INVALID_MAGIC_CODE]: { // [EAuthenticationErrorCodes.INVALID_MAGIC_CODE]: {
title: `Authentication failed`, // title: `Authentication failed`,
message: () => `Invalid magic code. Please try again.`, // message: () => `Invalid magic code. Please try again.`,
}, // },
[EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE]: { // [EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE]: {
title: `Expired magic code`, // title: `Expired magic code`,
message: () => `Expired magic code. Please try again.`, // message: () => `Expired magic code. Please try again.`,
}, // },
[EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED]: { // [EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED]: {
title: `Expired magic code`, // title: `Expired magic code`,
message: () => `Expired magic code. Please try again.`, // message: () => `Expired magic code. Please try again.`,
}, // },
// Oauth // // Oauth
[EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED]: { // [EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED]: {
title: `Google not configured`, // title: `Google not configured`,
message: () => `Google not configured. Please contact your administrator.`, // message: () => `Google not configured. Please contact your administrator.`,
}, // },
[EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED]: { // [EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED]: {
title: `GitHub not configured`, // title: `GitHub not configured`,
message: () => `GitHub not configured. Please contact your administrator.`, // message: () => `GitHub not configured. Please contact your administrator.`,
}, // },
[EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR]: { // [EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR]: {
title: `Google OAuth provider error`, // title: `Google OAuth provider error`,
message: () => `Google OAuth provider error. Please try again.`, // message: () => `Google OAuth provider error. Please try again.`,
}, // },
[EAuthenticationErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR]: { // [EAuthenticationErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR]: {
title: `GitHub OAuth provider error`, // title: `GitHub OAuth provider error`,
message: () => `GitHub OAuth provider error. Please try again.`, // message: () => `GitHub OAuth provider error. Please try again.`,
}, // },
// Reset Password // // Reset Password
[EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN]: { // [EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN]: {
title: `Invalid password token`, // title: `Invalid password token`,
message: () => `Invalid password token. Please try again.`, // message: () => `Invalid password token. Please try again.`,
}, // },
[EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN]: { // [EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN]: {
title: `Expired password token`, // title: `Expired password token`,
message: () => `Expired password token. Please try again.`, // message: () => `Expired password token. Please try again.`,
}, // },
// Change password // // Change password
[EAuthenticationErrorCodes.MISSING_PASSWORD]: { // [EAuthenticationErrorCodes.MISSING_PASSWORD]: {
title: `Password required`, // title: `Password required`,
message: () => `Password required. Please try again.`, // message: () => `Password required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD]: { // [EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD]: {
title: `Incorrect old password`, // title: `Incorrect old password`,
message: () => `Incorrect old password. Please try again.`, // message: () => `Incorrect old password. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_NEW_PASSWORD]: { // [EAuthenticationErrorCodes.INVALID_NEW_PASSWORD]: {
title: `Invalid new password`, // title: `Invalid new password`,
message: () => `Invalid new password. Please try again.`, // message: () => `Invalid new password. Please try again.`,
}, // },
// set password // // set password
[EAuthenticationErrorCodes.PASSWORD_ALREADY_SET]: { // [EAuthenticationErrorCodes.PASSWORD_ALREADY_SET]: {
title: `Password already set`, // title: `Password already set`,
message: () => `Password already set. Please try again.`, // message: () => `Password already set. Please try again.`,
}, // },
// admin // // admin
[EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST]: { // [EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST]: {
title: `Admin already exists`, // title: `Admin already exists`,
message: () => `Admin already exists. Please try again.`, // message: () => `Admin already exists. Please try again.`,
}, // },
[EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: { // [EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: {
title: `Email, password and first name required`, // title: `Email, password and first name required`,
message: () => `Email, password and first name required. Please try again.`, // message: () => `Email, password and first name required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL]: { // [EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL]: {
title: `Invalid admin email`, // title: `Invalid admin email`,
message: () => `Invalid admin email. Please try again.`, // message: () => `Invalid admin email. Please try again.`,
}, // },
[EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD]: { // [EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD]: {
title: `Invalid admin password`, // title: `Invalid admin password`,
message: () => `Invalid admin password. Please try again.`, // message: () => `Invalid admin password. Please try again.`,
}, // },
[EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: { // [EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: {
title: `Email and password required`, // title: `Email and password required`,
message: () => `Email and password required. Please try again.`, // message: () => `Email and password required. Please try again.`,
}, // },
[EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED]: { // [EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED]: {
title: `Authentication failed`, // title: `Authentication failed`,
message: () => `Authentication failed. Please try again.`, // message: () => `Authentication failed. Please try again.`,
}, // },
[EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST]: { // [EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST]: {
title: `Admin user already exists`, // title: `Admin user already exists`,
message: () => ( // message: () => (
<div> // <div>
Admin user already exists.&nbsp; // Admin user already exists.&nbsp;
<Link className="underline underline-offset-4 font-medium hover:font-bold transition-all" href={`/admin`}> // <Link className="underline underline-offset-4 font-medium hover:font-bold transition-all" href={`/admin`}>
Sign In // Sign In
</Link> // </Link>
&nbsp;now. // &nbsp;now.
</div> // </div>
), // ),
}, // },
[EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: { // [EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: {
title: `Admin user does not exist`, // title: `Admin user does not exist`,
message: () => ( // message: () => (
<div> // <div>
Admin user does not exist.&nbsp; // Admin user does not exist.&nbsp;
<Link className="underline underline-offset-4 font-medium hover:font-bold transition-all" href={`/admin`}> // <Link className="underline underline-offset-4 font-medium hover:font-bold transition-all" href={`/admin`}>
Sign In // Sign In
</Link> // </Link>
&nbsp;now. // &nbsp;now.
</div> // </div>
), // ),
}, // },
}; // };
export const authErrorHandler = ( // export const authErrorHandler = (
errorCode: EAuthenticationErrorCodes, // errorCode: EAuthenticationErrorCodes,
email?: string | undefined // email?: string | undefined
): TAuthErrorInfo | undefined => { // ): TAuthErrorInfo | undefined => {
const bannerAlertErrorCodes = [ // const bannerAlertErrorCodes = [
EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED, // EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED,
EAuthenticationErrorCodes.INVALID_EMAIL, // EAuthenticationErrorCodes.INVALID_EMAIL,
EAuthenticationErrorCodes.EMAIL_REQUIRED, // EAuthenticationErrorCodes.EMAIL_REQUIRED,
EAuthenticationErrorCodes.SIGNUP_DISABLED, // EAuthenticationErrorCodes.SIGNUP_DISABLED,
EAuthenticationErrorCodes.INVALID_PASSWORD, // EAuthenticationErrorCodes.INVALID_PASSWORD,
EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED, // EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED,
EAuthenticationErrorCodes.USER_ALREADY_EXIST, // EAuthenticationErrorCodes.USER_ALREADY_EXIST,
EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP, // EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP,
EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP, // EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP,
EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_UP, // EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_UP,
EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP, // EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP,
EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED, // EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED,
EAuthenticationErrorCodes.USER_DOES_NOT_EXIST, // EAuthenticationErrorCodes.USER_DOES_NOT_EXIST,
EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN, // EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN,
EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN, // EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN,
EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_IN, // EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_IN,
EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN, // EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED, // EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED,
EAuthenticationErrorCodes.INVALID_MAGIC_CODE, // // EAuthenticationErrorCodes.INVALID_MAGIC_CODE,
EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE, // // EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE,
EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED, // // EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED,
EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED, // EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED,
EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED, // EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED,
EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR, // EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR,
EAuthenticationErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR, // EAuthenticationErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR,
EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN, // EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN,
EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN, // EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN,
EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD, // EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD,
EAuthenticationErrorCodes.INVALID_NEW_PASSWORD, // EAuthenticationErrorCodes.INVALID_NEW_PASSWORD,
EAuthenticationErrorCodes.PASSWORD_ALREADY_SET, // EAuthenticationErrorCodes.PASSWORD_ALREADY_SET,
EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST, // EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST,
EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME, // EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME,
EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL, // EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL,
EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD, // EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD,
EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD, // EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD,
EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED, // EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED,
EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST, // EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST,
EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST, // EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
]; // ];
if (bannerAlertErrorCodes.includes(errorCode)) // if (bannerAlertErrorCodes.includes(errorCode))
return { // return {
type: EErrorAlertType.BANNER_ALERT, // type: EErrorAlertType.BANNER_ALERT,
code: errorCode, // code: errorCode,
title: errorCodeMessages[errorCode]?.title || "Error", // title: errorCodeMessages[errorCode]?.title || "Error",
message: errorCodeMessages[errorCode]?.message(email) || "Something went wrong. Please try again.", // message: errorCodeMessages[errorCode]?.message(email) || "Something went wrong. Please try again.",
}; // };
return undefined; // return undefined;
}; // };

View File

@ -8,6 +8,7 @@ module.exports = {
content: { content: {
relative: true, relative: true,
files: [ files: [
"./app/**/*.{js,ts,jsx,tsx}",
"./components/**/*.tsx", "./components/**/*.tsx",
"./constants/**/*.{js,ts,jsx,tsx}", "./constants/**/*.{js,ts,jsx,tsx}",
"./layouts/**/*.tsx", "./layouts/**/*.tsx",

View File

@ -1,5 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react"; import type { Meta, StoryObj } from "@storybook/react";
import React from "react"; import React from "react";
import { Draggable } from "./draggable";
import { Sortable } from "./sortable"; import { Sortable } from "./sortable";
const meta: Meta<typeof Sortable> = { const meta: Meta<typeof Sortable> = {
@ -12,7 +13,7 @@ type Story = StoryObj<typeof Sortable>;
const data = [ const data = [
{ id: "1", name: "John Doe" }, { id: "1", name: "John Doe" },
{ id: "2", name: "Satish" }, { id: "2", name: "Jane Doe 2" },
{ id: "3", name: "Alice" }, { id: "3", name: "Alice" },
{ id: "4", name: "Bob" }, { id: "4", name: "Bob" },
{ id: "5", name: "Charlie" }, { id: "5", name: "Charlie" },

42
space/types/project.d.ts vendored Normal file
View File

@ -0,0 +1,42 @@
import { TLogoProps } from "@plane/types";
export type TWorkspaceDetails = {
name: string;
slug: string;
id: string;
};
export type TViewDetails = {
list: boolean;
gantt: boolean;
kanban: boolean;
calendar: boolean;
spreadsheet: boolean;
};
export type TProjectDetails = {
id: string;
identifier: string;
name: string;
cover_image: string | undefined;
logo_props: TLogoProps;
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,3 +1,5 @@
"use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// ui // ui
import { Crown } from "lucide-react"; import { Crown } from "lucide-react";
@ -5,7 +7,7 @@ import { Breadcrumbs, ContrastIcon } from "@plane/ui";
import { BreadcrumbLink } from "@/components/common"; import { BreadcrumbLink } from "@/components/common";
// icons // icons
export const WorkspaceActiveCycleHeader = observer(() => ( const WorkspaceActiveCycleHeader = observer(() => (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4"> <div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap"> <div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -25,3 +27,5 @@ export const WorkspaceActiveCycleHeader = observer(() => (
</div> </div>
</div> </div>
)); ));
export default WorkspaceActiveCycleHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "../../app-header-wrapper";
import WorkspaceActiveCycleHeader from "./header";
const WorkspaceActiveCycleHeaderPage = () => <AppHeaderWrapper header={<WorkspaceActiveCycleHeader />} />;
export default WorkspaceActiveCycleHeaderPage;

View File

@ -1,17 +1,22 @@
"use client";
import { useEffect } from "react"; import { useEffect } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useSearchParams } from "next/navigation";
// icons
import { BarChart2, PanelRight } from "lucide-react"; import { BarChart2, PanelRight } from "lucide-react";
// ui // ui
import { Breadcrumbs } from "@plane/ui"; import { Breadcrumbs } from "@plane/ui";
// components // components
import { BreadcrumbLink } from "@/components/common"; import { BreadcrumbLink } from "@/components/common";
// helpers
import { cn } from "@/helpers/common.helper"; import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme } from "@/hooks/store"; import { useAppTheme } from "@/hooks/store";
export const WorkspaceAnalyticsHeader = observer(() => { const WorkspaceAnalyticsHeader = observer(() => {
const router = useRouter(); const searchParams = useSearchParams();
const { analytics_tab } = router.query; const analytics_tab = searchParams.get("analytics_tab");
// store hooks // store hooks
const { workspaceAnalyticsSidebarCollapsed, toggleWorkspaceAnalyticsSidebar } = useAppTheme(); const { workspaceAnalyticsSidebarCollapsed, toggleWorkspaceAnalyticsSidebar } = useAppTheme();
@ -66,3 +71,5 @@ export const WorkspaceAnalyticsHeader = observer(() => {
</> </>
); );
}); });
export default WorkspaceAnalyticsHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "../../app-header-wrapper";
import WorkspaceAnalyticsHeader from "./header";
const WorkspaceAnalyticsHeaderPage = () => <AppHeaderWrapper header={<WorkspaceAnalyticsHeader />} />;
export default WorkspaceAnalyticsHeaderPage;

View File

@ -1,18 +1,21 @@
"use client";
import Image from "next/image"; import Image from "next/image";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { Home, Zap } from "lucide-react"; import { Home, Zap } from "lucide-react";
// images // images
import githubBlackImage from "/public/logos/github-black.png"; import githubBlackImage from "/public/logos/github-black.png";
import githubWhiteImage from "/public/logos/github-white.png"; import githubWhiteImage from "/public/logos/github-white.png";
// hooks // ui
// components
import { Breadcrumbs } from "@plane/ui"; import { Breadcrumbs } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common"; import { BreadcrumbLink } from "@/components/common";
// constants // constants
import { CHANGELOG_REDIRECTED, GITHUB_REDIRECTED } from "@/constants/event-tracker"; import { CHANGELOG_REDIRECTED, GITHUB_REDIRECTED } from "@/constants/event-tracker";
// hooks
import { useEventTracker } from "@/hooks/store"; import { useEventTracker } from "@/hooks/store";
export const WorkspaceDashboardHeader = () => { const WorkspaceDashboardHeader = () => {
// hooks // hooks
const { captureEvent } = useEventTracker(); const { captureEvent } = useEventTracker();
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
@ -69,3 +72,5 @@ export const WorkspaceDashboardHeader = () => {
</> </>
); );
}; };
export default WorkspaceDashboardHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "../app-header-wrapper";
import WorkspaceDashboardHeader from "./header";
const WorkspaceDashboardHeaderPage = () => <AppHeaderWrapper header={<WorkspaceDashboardHeader />} />;
export default WorkspaceDashboardHeaderPage;

View File

@ -0,0 +1,8 @@
"use client";
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import UserProfileHeader from "../header";
const ProfileActivityHeader = () => <AppHeaderWrapper header={<UserProfileHeader type="Activity" />} />;
export default ProfileActivityHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import UserProfileHeader from "../header";
import ProfileIssuesMobileHeader from "../mobile-header";
const ProfileAssignedHeader = () => (
<AppHeaderWrapper header={<UserProfileHeader type="Assigned" />} mobileHeader={<ProfileIssuesMobileHeader />} />
);
export default ProfileAssignedHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import UserProfileHeader from "../header";
import ProfileIssuesMobileHeader from "../mobile-header";
const ProfileCreatedHeader = () => (
<AppHeaderWrapper header={<UserProfileHeader type="Created" />} mobileHeader={<ProfileIssuesMobileHeader />} />
);
export default ProfileCreatedHeader;

View File

@ -1,8 +1,10 @@
"use client";
// ui // ui
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
import { ChevronDown, PanelRight } from "lucide-react"; import { ChevronDown, PanelRight } from "lucide-react";
import { Breadcrumbs, CustomMenu } from "@plane/ui"; import { Breadcrumbs, CustomMenu } from "@plane/ui";
import { BreadcrumbLink } from "@/components/common"; import { BreadcrumbLink } from "@/components/common";
@ -15,11 +17,10 @@ type TUserProfileHeader = {
type?: string | undefined; type?: string | undefined;
}; };
export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => { const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
const { type = undefined } = props; const { type = undefined } = props;
// router // router
const router = useRouter(); const { workspaceSlug, userId } = useParams();
const { workspaceSlug, userId } = router.query;
// store hooks // store hooks
const { toggleProfileSidebar, profileSidebarCollapsed } = useAppTheme(); const { toggleProfileSidebar, profileSidebarCollapsed } = useAppTheme();
const { const {
@ -89,3 +90,5 @@ export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
</div> </div>
); );
}); });
export default UserProfileHeader;

View File

@ -1,6 +1,8 @@
"use client";
import { useCallback } from "react"; import { useCallback } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// icons // icons
import { ChevronDown } from "lucide-react"; import { ChevronDown } from "lucide-react";
// types // types
@ -18,8 +20,7 @@ import { useIssues, useLabel } from "@/hooks/store";
const ProfileIssuesMobileHeader = observer(() => { const ProfileIssuesMobileHeader = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug, userId } = useParams();
const { workspaceSlug, userId } = router.query;
// store hook // store hook
const { const {
issuesFilter: { issueFilters, updateFilters }, issuesFilter: { issueFilters, updateFilters },

View File

@ -0,0 +1,8 @@
"use client";
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import UserProfileHeader from "./header";
const ProfileOverviewHeader = () => <AppHeaderWrapper header={<UserProfileHeader type="Summary" />} />;
export default ProfileOverviewHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import UserProfileHeader from "../header";
import ProfileIssuesMobileHeader from "../mobile-header";
const ProfileSubscribedHeader = () => (
<AppHeaderWrapper header={<UserProfileHeader type="Subscribed" />} mobileHeader={<ProfileIssuesMobileHeader />} />
);
export default ProfileSubscribedHeader;

View File

@ -0,0 +1,2 @@
import DefaultProjectArchivesHeader from "../page";
export default DefaultProjectArchivesHeader;

View File

@ -1,6 +1,6 @@
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useParams, usePathname, useRouter } from "next/navigation";
// ui // ui
import { ArchiveIcon, Breadcrumbs, Tooltip } from "@plane/ui"; import { ArchiveIcon, Breadcrumbs, Tooltip } from "@plane/ui";
// components // components
@ -12,11 +12,12 @@ import { EIssuesStoreType } from "@/constants/issue";
import { useIssues, useProject } from "@/hooks/store"; import { useIssues, useProject } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os"; import { usePlatformOS } from "@/hooks/use-platform-os";
export const ProjectArchivesHeader: FC = observer(() => { const ProjectArchivesHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = useParams();
const activeTab = router.pathname.split("/").pop(); const pathname = usePathname();
const activeTab = pathname.split("/").pop();
// store hooks // store hooks
const { const {
issuesFilter: { issueFilters }, issuesFilter: { issueFilters },
@ -93,3 +94,5 @@ export const ProjectArchivesHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectArchivesHeader;

View File

@ -1,27 +1,23 @@
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// hooks
import { ArchiveIcon, Breadcrumbs, LayersIcon } from "@plane/ui";
import { BreadcrumbLink, Logo } from "@/components/common";
import { ISSUE_DETAILS } from "@/constants/fetch-keys";
import { useProject } from "@/hooks/store";
// components
// ui // ui
// types import { ArchiveIcon, Breadcrumbs, LayersIcon } from "@plane/ui";
import { IssueArchiveService } from "@/services/issue";
// constants
// services
// helpers
// components // components
import { BreadcrumbLink, Logo } from "@/components/common";
// constants
import { ISSUE_DETAILS } from "@/constants/fetch-keys";
// hooks
import { useProject } from "@/hooks/store";
// services
import { IssueArchiveService } from "@/services/issue";
const issueArchiveService = new IssueArchiveService(); const issueArchiveService = new IssueArchiveService();
export const ProjectArchivedIssueDetailsHeader: FC = observer(() => { const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug, projectId, archivedIssueId } = useParams();
const { workspaceSlug, projectId, archivedIssueId } = router.query;
// store hooks // store hooks
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
@ -96,3 +92,5 @@ export const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectArchivedIssueDetailsHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectArchivedIssueDetailsHeader from "./header";
const ProjectArchivedIssueDetailsHeaderPage = () => <AppHeaderWrapper header={<ProjectArchivedIssueDetailsHeader />} />;
export default ProjectArchivedIssueDetailsHeaderPage;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectArchivesHeader from "./header";
const ProjectArchivesHeaderPage = () => <AppHeaderWrapper header={<ProjectArchivesHeader />} />;
export default ProjectArchivesHeaderPage;

View File

@ -1,7 +1,7 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// icons // icons
import { ArrowRight, PanelRight } from "lucide-react"; import { ArrowRight, PanelRight } from "lucide-react";
// types // types
@ -36,8 +36,7 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => { const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => {
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { getCycleById } = useCycle(); const { getCycleById } = useCycle();
// derived values // derived values
@ -56,12 +55,12 @@ const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => {
); );
}; };
export const CycleIssuesHeader: React.FC = observer(() => { const CycleIssuesHeader: React.FC = observer(() => {
// states // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId } = router.query as { const { workspaceSlug, projectId, cycleId } = useParams() as {
workspaceSlug: string; workspaceSlug: string;
projectId: string; projectId: string;
cycleId: string; cycleId: string;
@ -206,9 +205,8 @@ export const CycleIssuesHeader: React.FC = observer(() => {
{issuesCount && issuesCount > 0 ? ( {issuesCount && issuesCount > 0 ? (
<Tooltip <Tooltip
isMobile={isMobile} isMobile={isMobile}
tooltipContent={`There are ${issuesCount} ${ tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
issuesCount > 1 ? "issues" : "issue" } in this cycle`}
} in this cycle`}
position="bottom" position="bottom"
> >
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100"> <span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
@ -303,3 +301,5 @@ export const CycleIssuesHeader: React.FC = observer(() => {
</> </>
); );
}); });
export default CycleIssuesHeader;

View File

@ -1,5 +1,5 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import router from "next/router"; import { useParams } from "next/navigation";
// icons // icons
import { Calendar, ChevronDown, Kanban, List } from "lucide-react"; import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
// types // types
@ -16,7 +16,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks // hooks
import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store"; import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store";
export const CycleMobileHeader = () => { const CycleIssuesMobileHeader = () => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
const { getCycleById } = useCycle(); const { getCycleById } = useCycle();
const layouts = [ const layouts = [
@ -25,7 +25,7 @@ export const CycleMobileHeader = () => {
{ key: "calendar", title: "Calendar", icon: Calendar }, { key: "calendar", title: "Calendar", icon: Calendar },
]; ];
const { workspaceSlug, projectId, cycleId } = router.query; const { workspaceSlug, projectId, cycleId } = useParams();
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
// store hooks // store hooks
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
@ -202,3 +202,5 @@ export const CycleMobileHeader = () => {
</> </>
); );
}; };
export default CycleIssuesMobileHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import CycleIssuesHeader from "./header";
import CycleIssuesMobileHeader from "./mobile-header";
const CycleIssuesHeaderPage = () => (
<AppHeaderWrapper header={<CycleIssuesHeader />} mobileHeader={<CycleIssuesMobileHeader />} />
);
export default CycleIssuesHeaderPage;

View File

@ -1,6 +1,6 @@
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// ui // ui
import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui"; import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui";
// components // components
@ -11,10 +11,10 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
export const CyclesHeader: FC = observer(() => { const CyclesHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = useParams();
// store hooks // store hooks
const { toggleCreateCycleModal } = useCommandPalette(); const { toggleCreateCycleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker(); const { setTrackElement } = useEventTracker();
@ -72,3 +72,5 @@ export const CyclesHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default CyclesHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import CyclesHeader from "./header";
import CyclesListMobileHeader from "./mobile-header";
const CyclesHeaderPage = () => (
<AppHeaderWrapper header={<CyclesHeader />} mobileHeader={<CyclesListMobileHeader />} />
);
export default CyclesHeaderPage;

View File

@ -1,6 +1,6 @@
import { FC, useCallback } from "react"; import { FC, useCallback } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// types // types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types"; import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
// ui // ui
@ -16,10 +16,9 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store"; import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os"; import { usePlatformOS } from "@/hooks/use-platform-os";
export const ProjectDraftIssueHeader: FC = observer(() => { const ProjectDraftIssueHeader: FC = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string };
// store hooks // store hooks
const { const {
issuesFilter: { issueFilters, updateFilters }, issuesFilter: { issueFilters, updateFilters },
@ -168,3 +167,5 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectDraftIssueHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectDraftIssueHeader from "./header";
const ProjectDraftIssueHeaderPage = () => <AppHeaderWrapper header={<ProjectDraftIssueHeader />} />;
export default ProjectDraftIssueHeaderPage;

View File

@ -1,6 +1,6 @@
import { FC, useState } from "react"; import { FC, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
import { RefreshCcw } from "lucide-react"; import { RefreshCcw } from "lucide-react";
// ui // ui
import { Breadcrumbs, Button, LayersIcon } from "@plane/ui"; import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
@ -10,12 +10,11 @@ import { InboxIssueCreateEditModalRoot } from "@/components/inbox";
// hooks // hooks
import { useProject, useProjectInbox } from "@/hooks/store"; import { useProject, useProjectInbox } from "@/hooks/store";
export const ProjectInboxHeader: FC = observer(() => { const ProjectInboxHeader: FC = observer(() => {
// states // states
const [createIssueModal, setCreateIssueModal] = useState(false); const [createIssueModal, setCreateIssueModal] = useState(false);
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
const { loader } = useProjectInbox(); const { loader } = useProjectInbox();
@ -77,3 +76,5 @@ export const ProjectInboxHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectInboxHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectInboxHeader from "./header";
const ProjectInboxHeaderPage = () => <AppHeaderWrapper header={<ProjectInboxHeader />} />;
export default ProjectInboxHeaderPage;

View File

@ -1,22 +1,20 @@
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// hooks
import { PanelRight } from "lucide-react"; import { PanelRight } from "lucide-react";
import { Breadcrumbs, LayersIcon } from "@plane/ui";
import { BreadcrumbLink, Logo } from "@/components/common";
import { cn } from "@/helpers/common.helper";
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
// ui // ui
// helpers import { Breadcrumbs, LayersIcon } from "@plane/ui";
// services
// constants
// components // components
import { BreadcrumbLink, Logo } from "@/components/common";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
export const ProjectIssueDetailsHeader: FC = observer(() => { const ProjectIssueDetailsHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = useParams();
// store hooks // store hooks
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
const { issueDetailSidebarCollapsed, toggleIssueDetailSidebar } = useAppTheme(); const { issueDetailSidebarCollapsed, toggleIssueDetailSidebar } = useAppTheme();
@ -83,3 +81,5 @@ export const ProjectIssueDetailsHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectIssueDetailsHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectIssueDetailsHeader from "./header";
const ProjectIssueDetailsHeaderPage = () => <AppHeaderWrapper header={<ProjectIssueDetailsHeader />} />;
export default ProjectIssueDetailsHeaderPage;

View File

@ -1,6 +1,6 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// icons // icons
import { Briefcase, Circle, ExternalLink } from "lucide-react"; import { Briefcase, Circle, ExternalLink } from "lucide-react";
// types // types
@ -30,12 +30,12 @@ import {
import { useIssues } from "@/hooks/store/use-issues"; import { useIssues } from "@/hooks/store/use-issues";
import { usePlatformOS } from "@/hooks/use-platform-os"; import { usePlatformOS } from "@/hooks/use-platform-os";
export const ProjectIssuesHeader: React.FC = observer(() => { const ProjectIssuesHeader: React.FC = observer(() => {
// states // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string }; const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
// store hooks // store hooks
const { const {
project: { projectMemberIds }, project: { projectMemberIds },
@ -234,3 +234,5 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
</> </>
); );
}); });
export default ProjectIssuesHeader;

View File

@ -1,6 +1,6 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import router from "next/router"; import { useParams } from "next/navigation";
// icons // icons
import { Calendar, ChevronDown, Kanban, List } from "lucide-react"; import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
// types // types
@ -17,14 +17,14 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks // hooks
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store"; import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
export const IssuesMobileHeader = observer(() => { const ProjectIssuesMobileHeader = observer(() => {
const layouts = [ const layouts = [
{ key: "list", title: "List", icon: List }, { key: "list", title: "List", icon: List },
{ key: "kanban", title: "Kanban", icon: Kanban }, { key: "kanban", title: "Kanban", icon: Kanban },
{ key: "calendar", title: "Calendar", icon: Calendar }, { key: "calendar", title: "Calendar", icon: Calendar },
]; ];
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
const { workspaceSlug, projectId } = router.query as { const { workspaceSlug, projectId } = useParams() as {
workspaceSlug: string; workspaceSlug: string;
projectId: string; projectId: string;
}; };
@ -180,3 +180,5 @@ export const IssuesMobileHeader = observer(() => {
</> </>
); );
}); });
export default ProjectIssuesMobileHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectIssuesHeader from "./header";
import ProjectIssuesMobileHeader from "./mobile-header";
const ProjectIssuesHeaderPage = () => (
<AppHeaderWrapper header={<ProjectIssuesHeader />} mobileHeader={<ProjectIssuesMobileHeader />} />
);
export default ProjectIssuesHeaderPage;

View File

@ -1,7 +1,7 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// icons // icons
import { ArrowRight, PanelRight } from "lucide-react"; import { ArrowRight, PanelRight } from "lucide-react";
// types // types
@ -37,8 +37,7 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => { const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => {
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { getModuleById } = useModule(); const { getModuleById } = useModule();
// derived values // derived values
@ -59,12 +58,12 @@ const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => {
); );
}; };
export const ModuleIssuesHeader: React.FC = observer(() => { const ModuleIssuesHeader: React.FC = observer(() => {
// states // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query; const { workspaceSlug, projectId, moduleId } = useParams();
// hooks // hooks
const { isMobile } = usePlatformOS(); const { isMobile } = usePlatformOS();
// store hooks // store hooks
@ -206,9 +205,8 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
{issuesCount && issuesCount > 0 ? ( {issuesCount && issuesCount > 0 ? (
<Tooltip <Tooltip
isMobile={isMobile} isMobile={isMobile}
tooltipContent={`There are ${issuesCount} ${ tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
issuesCount > 1 ? "issues" : "issue" } in this module`}
} in this module`}
position="bottom" position="bottom"
> >
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100"> <span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
@ -310,3 +308,5 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
</> </>
); );
}); });
export default ModuleIssuesHeader;

View File

@ -1,6 +1,6 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import router from "next/router"; import { useParams } from "next/navigation";
// icons // icons
import { Calendar, ChevronDown, Kanban, List } from "lucide-react"; import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
// types // types
@ -17,7 +17,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks // hooks
import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store"; import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
export const ModuleMobileHeader = observer(() => { const ModuleIssuesMobileHeader = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
const { getModuleById } = useModule(); const { getModuleById } = useModule();
@ -26,7 +26,7 @@ export const ModuleMobileHeader = observer(() => {
{ key: "kanban", title: "Kanban", icon: Kanban }, { key: "kanban", title: "Kanban", icon: Kanban },
{ key: "calendar", title: "Calendar", icon: Calendar }, { key: "calendar", title: "Calendar", icon: Calendar },
]; ];
const { workspaceSlug, projectId, moduleId } = router.query as { const { workspaceSlug, projectId, moduleId } = useParams() as {
workspaceSlug: string; workspaceSlug: string;
projectId: string; projectId: string;
moduleId: string; moduleId: string;
@ -183,3 +183,5 @@ export const ModuleMobileHeader = observer(() => {
</div> </div>
); );
}); });
export default ModuleIssuesMobileHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ModuleIssuesHeader from "./header";
import ModuleIssuesMobileHeader from "./mobile-header";
const ModuleIssuesHeaderPage = () => (
<AppHeaderWrapper header={<ModuleIssuesHeader />} mobileHeader={<ModuleIssuesMobileHeader />} />
);
export default ModuleIssuesHeaderPage;

View File

@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// ui // ui
import { Breadcrumbs, Button, DiceIcon } from "@plane/ui"; import { Breadcrumbs, Button, DiceIcon } from "@plane/ui";
// components // components
@ -10,10 +10,10 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
export const ModulesListHeader: React.FC = observer(() => { const ModulesListHeader: React.FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = useParams();
// store hooks // store hooks
const { toggleCreateModuleModal } = useCommandPalette(); const { toggleCreateModuleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker(); const { setTrackElement } = useEventTracker();
@ -72,3 +72,5 @@ export const ModulesListHeader: React.FC = observer(() => {
</div> </div>
); );
}); });
export default ModulesListHeader;

View File

@ -0,0 +1,12 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ModulesListHeader from "./header";
import ModulesListMobileHeader from "./mobile-header";
const ModulesHeaderPage = () => (
<AppHeaderWrapper header={<ModulesListHeader />} mobileHeader={<ModulesListMobileHeader />} />
);
export default ModulesHeaderPage;

View File

@ -0,0 +1,170 @@
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { FileText } from "lucide-react";
// types
import { TLogoProps } from "@plane/types";
// ui
import { Breadcrumbs, Button, EmojiIconPicker, EmojiIconPickerTypes, TOAST_TYPE, setToast } from "@plane/ui";
// components
import { BreadcrumbLink, Logo } from "@/components/common";
// helper
import { convertHexEmojiToDecimal } from "@/helpers/emoji.helper";
// hooks
import { usePage, useProject } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
export interface IPagesHeaderProps {
showButton?: boolean;
}
const PageDetailsHeader = observer(() => {
// router
const { workspaceSlug, pageId } = useParams();
// state
const [isOpen, setIsOpen] = useState(false);
// store hooks
const { currentProjectDetails } = useProject();
const { isContentEditable, isSubmitting, name, logo_props, updatePageLogo } = usePage(pageId?.toString() ?? "");
const handlePageLogoUpdate = async (data: TLogoProps) => {
if (data) {
updatePageLogo(data)
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Logo Updated successfully.",
});
})
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Something went wrong. Please try again.",
});
});
}
};
// use platform
const { platform } = usePlatformOS();
// derived values
const isMac = platform === "MacOS";
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<span>
<span className="hidden md:block">
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
label={currentProjectDetails?.name ?? "Project"}
icon={
currentProjectDetails && (
<span className="grid h-4 w-4 flex-shrink-0 place-items-center">
<Logo logo={currentProjectDetails?.logo_props} size={16} />
</span>
)
}
/>
</span>
<span className="md:hidden">
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
label={"..."}
/>
</span>
</span>
}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages`}
label="Pages"
icon={<FileText className="h-4 w-4 text-custom-text-300" />}
/>
}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
label={name ?? "Page"}
icon={
<EmojiIconPicker
isOpen={isOpen}
handleToggle={(val: boolean) => setIsOpen(val)}
className="flex items-center justify-center"
buttonClassName="flex items-center justify-center"
label={
<>
{logo_props?.in_use ? (
<Logo logo={logo_props} size={16} type="lucide" />
) : (
<FileText className="h-4 w-4 text-custom-text-300" />
)}
</>
}
onChange={(val) => {
let logoValue = {};
if (val?.type === "emoji")
logoValue = {
value: convertHexEmojiToDecimal(val.value.unified),
url: val.value.imageUrl,
};
else if (val?.type === "icon") logoValue = val.value;
handlePageLogoUpdate({
in_use: val?.type,
[val?.type]: logoValue,
}).finally(() => setIsOpen(false));
}}
defaultIconColor={
logo_props?.in_use && logo_props.in_use === "icon" ? logo_props?.icon?.color : undefined
}
defaultOpen={
logo_props?.in_use && logo_props?.in_use === "emoji"
? EmojiIconPickerTypes.EMOJI
: EmojiIconPickerTypes.ICON
}
/>
}
/>
}
/>
</Breadcrumbs>
</div>
</div>
{isContentEditable && (
<Button
variant="primary"
size="sm"
onClick={() => {
// ctrl/cmd + s to save the changes
const event = new KeyboardEvent("keydown", {
key: "s",
ctrlKey: !isMac,
metaKey: isMac,
});
window.dispatchEvent(event);
}}
className="flex-shrink-0"
loading={isSubmitting === "submitting"}
>
{isSubmitting === "submitting" ? "Saving" : "Save changes"}
</Button>
)}
</div>
);
});
export default PageDetailsHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import PageDetailsHeader from "./header";
const PageDetailsHeaderPage = () => <AppHeaderWrapper header={<PageDetailsHeader />} />;
export default PageDetailsHeaderPage;

View File

@ -1,5 +1,5 @@
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useSearchParams } from "next/navigation";
import { FileText } from "lucide-react"; import { FileText } from "lucide-react";
// ui // ui
import { Breadcrumbs, Button } from "@plane/ui"; import { Breadcrumbs, Button } from "@plane/ui";
@ -11,10 +11,11 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
export const PagesHeader = observer(() => { const PagesHeader = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug } = useParams();
const { workspaceSlug, type: pageType } = router.query; const searchParams = useSearchParams();
const pageType = searchParams.get("type");
// store hooks // store hooks
const { toggleCreatePageModal } = useCommandPalette(); const { toggleCreatePageModal } = useCommandPalette();
const { const {
@ -74,3 +75,5 @@ export const PagesHeader = observer(() => {
</div> </div>
); );
}); });
export default PagesHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import PagesHeader from "./header";
const PagesHeaderPage = () => <AppHeaderWrapper header={<PagesHeader />} />;
export default PagesHeaderPage;

View File

@ -0,0 +1,2 @@
import DefaultProjectSettingHeader from "../page";
export default DefaultProjectSettingHeader;

View File

@ -1,6 +1,6 @@
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
// ui // ui
import { Settings } from "lucide-react"; import { Settings } from "lucide-react";
import { Breadcrumbs, CustomMenu } from "@plane/ui"; import { Breadcrumbs, CustomMenu } from "@plane/ui";
@ -11,10 +11,10 @@ import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
// hooks // hooks
import { useProject, useUser } from "@/hooks/store"; import { useProject, useUser } from "@/hooks/store";
export const ProjectSettingHeader: FC = observer(() => { const ProjectSettingHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = useParams();
// store hooks // store hooks
const { const {
membership: { currentProjectRole }, membership: { currentProjectRole },
@ -80,3 +80,5 @@ export const ProjectSettingHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectSettingHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectSettingHeader from "./header";
const ProjectSettingHeaderPage = () => <AppHeaderWrapper header={<ProjectSettingHeader />} />;
export default ProjectSettingHeaderPage;

View File

@ -1,7 +1,7 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// types // types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types"; import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
// ui // ui
@ -28,10 +28,9 @@ import {
useUser, useUser,
} from "@/hooks/store"; } from "@/hooks/store";
export const ProjectViewIssuesHeader: React.FC = observer(() => { const ProjectViewIssuesHeader: React.FC = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug, projectId, viewId } = useParams();
const { workspaceSlug, projectId, viewId } = router.query;
// store hooks // store hooks
const { const {
issuesFilter: { issueFilters, updateFilters }, issuesFilter: { issueFilters, updateFilters },
@ -256,3 +255,5 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectViewIssuesHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectViewIssuesHeader from "./header";
const ProjectViewIssuesHeaderPage = () => <AppHeaderWrapper header={<ProjectViewIssuesHeader />} />;
export default ProjectViewIssuesHeaderPage;

View File

@ -1,5 +1,5 @@
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// ui // ui
import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui"; import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui";
// components // components
@ -10,10 +10,9 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useCommandPalette, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useProject, useUser } from "@/hooks/store";
export const ProjectViewsHeader: React.FC = observer(() => { const ProjectViewsHeader: React.FC = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug } = useParams();
const { workspaceSlug } = router.query;
// store hooks // store hooks
const { toggleCreateViewModal } = useCommandPalette(); const { toggleCreateViewModal } = useCommandPalette();
const { const {
@ -69,3 +68,5 @@ export const ProjectViewsHeader: React.FC = observer(() => {
</> </>
); );
}); });
export default ProjectViewsHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectViewsHeader from "./header";
const ProjectViewsHeaderPage = () => <AppHeaderWrapper header={<ProjectViewsHeader />} />;
export default ProjectViewsHeaderPage;

View File

@ -18,7 +18,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
import { useAppRouter, useCommandPalette, useEventTracker, useMember, useProjectFilter, useUser } from "@/hooks/store"; import { useAppRouter, useCommandPalette, useEventTracker, useMember, useProjectFilter, useUser } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
export const ProjectsHeader = observer(() => { const ProjectsHeader = observer(() => {
// states // states
const [isSearchOpen, setIsSearchOpen] = useState(false); const [isSearchOpen, setIsSearchOpen] = useState(false);
// refs // refs
@ -181,3 +181,5 @@ export const ProjectsHeader = observer(() => {
</div> </div>
); );
}); });
export default ProjectsHeader;

View File

@ -0,0 +1,13 @@
"use client";
// components
import AppHeaderWrapper from "@/app/[workspaceSlug]/app-header-wrapper";
import ProjectsHeader from "./header";
import ProjectsMobileHeader from "./mobile-header";
const ProjectsHeaderPage = () => (
<AppHeaderWrapper header={<ProjectsHeader />} mobileHeader={<ProjectsMobileHeader />} />
);
export default ProjectsHeaderPage;

View File

@ -0,0 +1,2 @@
import DefaultWorkspaceSettingsHeader from "../page";
export default DefaultWorkspaceSettingsHeader;

View File

@ -1,3 +1,5 @@
"use client";
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react";; import { observer } from "mobx-react";;
import { Settings } from "lucide-react"; import { Settings } from "lucide-react";
@ -8,7 +10,7 @@ import { BreadcrumbLink } from "@/components/common";
// hooks // hooks
import { useWorkspace } from "@/hooks/store"; import { useWorkspace } from "@/hooks/store";
export const WorkspaceSettingHeader: FC = observer(() => { const WorkspaceSettingHeader: FC = observer(() => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
return ( return (
@ -33,3 +35,5 @@ export const WorkspaceSettingHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default WorkspaceSettingHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "../../app-header-wrapper";
import WorkspaceSettingHeader from "./header";
const WorkspaceSettingHeaderPage = () => <AppHeaderWrapper header={<WorkspaceSettingHeader />} />;
export default WorkspaceSettingHeaderPage;

View File

@ -0,0 +1,2 @@
import DefaultWorkspaceViewsHeader from "../page";
export default DefaultWorkspaceViewsHeader;

View File

@ -1,6 +1,8 @@
"use client";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// types // types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types"; import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
// ui // ui
@ -17,12 +19,11 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks // hooks
import { useLabel, useMember, useUser, useIssues } from "@/hooks/store"; import { useLabel, useMember, useUser, useIssues } from "@/hooks/store";
export const GlobalIssuesHeader: React.FC = observer(() => { const GlobalIssuesHeader: React.FC = observer(() => {
// states // states
const [createViewModal, setCreateViewModal] = useState(false); const [createViewModal, setCreateViewModal] = useState(false);
// router // router
const router = useRouter(); const { workspaceSlug, globalViewId } = useParams();
const { workspaceSlug, globalViewId } = router.query;
// store hooks // store hooks
const { const {
issuesFilter: { filters, updateFilters }, issuesFilter: { filters, updateFilters },
@ -143,3 +144,5 @@ export const GlobalIssuesHeader: React.FC = observer(() => {
</> </>
); );
}); });
export default GlobalIssuesHeader;

View File

@ -0,0 +1,9 @@
"use client";
// components
import AppHeaderWrapper from "../../app-header-wrapper";
import GlobalIssuesHeader from "./header";
const GlobalIssuesHeaderPage = () => <AppHeaderWrapper header={<GlobalIssuesHeader />} />;
export default GlobalIssuesHeaderPage;

View File

@ -1,17 +1,13 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { WorkspaceActiveCycleHeader } from "@/components/headers";
import { WorkspaceActiveCyclesUpgrade } from "@/components/workspace"; import { WorkspaceActiveCyclesUpgrade } from "@/components/workspace";
// layouts
import { useWorkspace } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
// hooks // hooks
import { useWorkspace } from "@/hooks/store";
const WorkspaceActiveCyclesPage: NextPageWithLayout = observer(() => { const WorkspaceActiveCyclesPage = observer(() => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
// derived values // derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Active Cycles` : undefined; const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Active Cycles` : undefined;
@ -24,8 +20,4 @@ const WorkspaceActiveCyclesPage: NextPageWithLayout = observer(() => {
); );
}); });
WorkspaceActiveCyclesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<WorkspaceActiveCycleHeader />}>{page}</AppLayout>;
};
export default WorkspaceActiveCyclesPage; export default WorkspaceActiveCyclesPage;

View File

@ -1,25 +1,22 @@
import React, { Fragment, ReactElement } from "react"; "use client";
import React, { Fragment } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useSearchParams } from "next/navigation";
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
// components // components
import { CustomAnalytics, ScopeAndDemand } from "@/components/analytics"; import { CustomAnalytics, ScopeAndDemand } from "@/components/analytics";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { EmptyState } from "@/components/empty-state"; import { EmptyState } from "@/components/empty-state";
import { WorkspaceAnalyticsHeader } from "@/components/headers";
// constants // constants
import { ANALYTICS_TABS } from "@/constants/analytics"; import { ANALYTICS_TABS } from "@/constants/analytics";
import { EmptyStateType } from "@/constants/empty-state"; import { EmptyStateType } from "@/constants/empty-state";
// hooks // hooks
import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store"; import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";;
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const AnalyticsPage: NextPageWithLayout = observer(() => { const AnalyticsPage = observer(() => {
const router = useRouter(); const searchParams = useSearchParams();
const { analytics_tab } = router.query; const analytics_tab = searchParams.get("analytics_tab");
// store hooks // store hooks
const { toggleCreateProjectModal } = useCommandPalette(); const { toggleCreateProjectModal } = useCommandPalette();
const { setTrackElement } = useEventTracker(); const { setTrackElement } = useEventTracker();
@ -39,9 +36,8 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
<Tab key={tab.key} as={Fragment}> <Tab key={tab.key} as={Fragment}>
{({ selected }) => ( {({ selected }) => (
<button <button
className={`text-sm group relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium outline-none ${ className={`text-sm group relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium outline-none ${selected ? "text-custom-primary-100 " : "hover:text-custom-text-200"
selected ? "text-custom-primary-100 " : "hover:text-custom-text-200" }`}
}`}
> >
{tab.title} {tab.title}
<div <div
@ -75,8 +71,4 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
); );
}); });
AnalyticsPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<WorkspaceAnalyticsHeader />}>{page}</AppLayout>;
};
export default AnalyticsPage; export default AnalyticsPage;

View File

@ -0,0 +1,26 @@
"use client";
import { ReactNode } from "react";
// components
import { SidebarHamburgerToggle } from "@/components/core";
export interface IAppHeaderWrapper {
header: ReactNode;
mobileHeader?: ReactNode;
}
const AppHeaderWrapper = ({ header, mobileHeader }: IAppHeaderWrapper) => (
<>
<div className="z-[15]">
<div className="z-10 flex w-full items-center border-b border-custom-border-200">
<div className="block bg-custom-sidebar-background-100 py-4 pl-5 md:hidden">
<SidebarHamburgerToggle />
</div>
<div className="w-full">{header}</div>
</div>
{mobileHeader && mobileHeader}
</div>
</>
);
export default AppHeaderWrapper;

View File

@ -0,0 +1,25 @@
"use client";
import { CommandPalette } from "@/components/command-palette";
import { WorkspaceAuthWrapper } from "@/layouts/auth-layout";
import { AuthenticationWrapper } from "@/lib/wrappers";
import AppSidebar from "./sidebar";
export default function WorkspaceLayout({ header, children }: { header: React.ReactNode; children: React.ReactNode }) {
return (
<AuthenticationWrapper>
<CommandPalette />
<WorkspaceAuthWrapper>
<div className="relative flex h-screen w-full overflow-hidden">
<AppSidebar />
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
{header}
<div className="h-full w-full overflow-hidden">
<div className="relative h-full w-full overflow-x-hidden overflow-y-scroll">{children}</div>
</div>
</main>
</div>
</WorkspaceAuthWrapper>
</AuthenticationWrapper>
);
}

View File

@ -1,17 +1,13 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// layouts
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { WorkspaceDashboardHeader } from "@/components/headers/workspace-dashboard";
import { WorkspaceDashboardView } from "@/components/page-views"; import { WorkspaceDashboardView } from "@/components/page-views";
// types
// hooks // hooks
import { useWorkspace } from "@/hooks/store"; import { useWorkspace } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
import { NextPageWithLayout } from "@/lib/types";
const WorkspacePage: NextPageWithLayout = observer(() => { const WorkspacePage = observer(() => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
// derived values // derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Home` : undefined; const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Home` : undefined;
@ -24,8 +20,4 @@ const WorkspacePage: NextPageWithLayout = observer(() => {
); );
}); });
WorkspacePage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<WorkspaceDashboardHeader />}>{page}</AppLayout>;
};
export default WorkspacePage; export default WorkspacePage;

View File

@ -1,31 +1,27 @@
import { ReactElement, useState } from "react"; "use client";
import { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// hooks
import { Button } from "@plane/ui";
import { UserProfileHeader } from "@/components/headers";
import { DownloadActivityButton, WorkspaceActivityListPage } from "@/components/profile";
import { EUserWorkspaceRoles } from "@/constants/workspace";
import { useUser } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
import { ProfileAuthWrapper } from "@/layouts/user-profile-layout";
// components
// ui // ui
// types import { Button } from "@plane/ui";
import { NextPageWithLayout } from "@/lib/types"; // components
import { DownloadActivityButton, WorkspaceActivityListPage } from "@/components/profile";
// constants // constants
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser } from "@/hooks/store";
const PER_PAGE = 100; const PER_PAGE = 100;
const ProfileActivityPage: NextPageWithLayout = observer(() => { const ProfileActivityPage = observer(() => {
// states // states
const [pageCount, setPageCount] = useState(1); const [pageCount, setPageCount] = useState(1);
const [totalPages, setTotalPages] = useState(0); const [totalPages, setTotalPages] = useState(0);
const [resultsCount, setResultsCount] = useState(0); const [resultsCount, setResultsCount] = useState(0);
// router // router
const router = useRouter();
const { userId } = router.query; const { userId } = useParams();
// store hooks // store hooks
const { data: currentUser } = useUser(); const { data: currentUser } = useUser();
const { const {
@ -73,12 +69,4 @@ const ProfileActivityPage: NextPageWithLayout = observer(() => {
); );
}); });
ProfileActivityPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<UserProfileHeader type="Activity" />}>
<ProfileAuthWrapper>{page}</ProfileAuthWrapper>
</AppLayout>
);
};
export default ProfileActivityPage; export default ProfileActivityPage;

View File

@ -0,0 +1,15 @@
"use client";
import React from "react";
// components
import { PageHead } from "@/components/core";
import { ProfileIssuesPage } from "@/components/profile/profile-issues";
const ProfileAssignedIssuesPage = () => (
<>
<PageHead title="Profile - Assigned" />
<ProfileIssuesPage type="assigned" />
</>
);
export default ProfileAssignedIssuesPage;

View File

@ -0,0 +1,16 @@
"use client";
// store
import { observer } from "mobx-react-lite";
// components
import { PageHead } from "@/components/core";
import { ProfileIssuesPage } from "@/components/profile/profile-issues";
const ProfileCreatedIssuesPage = () => (
<>
<PageHead title="Profile - Created" />
<ProfileIssuesPage type="created" />
</>
);
export default observer(ProfileCreatedIssuesPage);

View File

@ -1,45 +1,51 @@
"use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { usePathname } from "next/navigation";
// components // components
import { ProfileNavbar, ProfileSidebar } from "@/components/profile"; import { ProfileSidebar } from "@/components/profile";
// constants // constants
import { EUserWorkspaceRoles } from "@/constants/workspace"; import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks // hooks
import { useUser } from "@/hooks/store"; import { useUser } from "@/hooks/store";
// local components
import { ProfileNavbar } from "./navbar";
type Props = { type Props = {
children: React.ReactNode; children: React.ReactNode;
className?: string;
showProfileIssuesFilter?: boolean;
}; };
const AUTHORIZED_ROLES = [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.VIEWER]; const AUTHORIZED_ROLES = [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.VIEWER];
export const ProfileAuthWrapper: React.FC<Props> = observer((props) => { const ProfileAuthWrapper: React.FC<Props> = observer((props) => {
const { children, className, showProfileIssuesFilter } = props; const { children } = props;
// router // router
const router = useRouter(); const pathname = usePathname();
// store hooks // store hooks
const { const {
membership: { currentWorkspaceRole }, membership: { currentWorkspaceRole },
} = useUser(); } = useUser();
// derived values // derived values
const isAuthorized = currentWorkspaceRole && AUTHORIZED_ROLES.includes(currentWorkspaceRole); const isAuthorized = currentWorkspaceRole && AUTHORIZED_ROLES.includes(currentWorkspaceRole);
const isAuthorizedPath = router.pathname.includes("assigned" || "created" || "subscribed"); const isAuthorizedPath =
pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
const isIssuesTab = pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
return ( return (
<div className="h-full w-full flex md:overflow-hidden"> <div className="h-full w-full flex md:overflow-hidden">
<div className="flex w-full flex-col md:h-full md:overflow-hidden"> <div className="flex w-full flex-col md:h-full md:overflow-hidden">
<ProfileNavbar isAuthorized={!!isAuthorized} showProfileIssuesFilter={showProfileIssuesFilter} /> <ProfileNavbar isAuthorized={!!isAuthorized} showProfileIssuesFilter={isIssuesTab} />
{isAuthorized || !isAuthorizedPath ? ( {isAuthorized || !isAuthorizedPath ? (
<div className={`w-full overflow-hidden md:h-full ${className}`}>{children}</div> <div className={`w-full overflow-hidden md:h-full`}>{children}</div>
) : ( ) : (
<div className="grid h-full w-full place-items-center text-custom-text-200"> <div className="grid h-full w-full place-items-center text-custom-text-200">
You do not have the permission to access this page. You do not have the permission to access this page.
</div> </div>
)} )}
</div> </div>
<ProfileSidebar /> <ProfileSidebar />
</div> </div>
); );
}); });
export default ProfileAuthWrapper;

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams, usePathname } from "next/navigation";
// components // components
import { ProfileIssuesFilter } from "@/components/profile"; import { ProfileIssuesFilter } from "@/components/profile";
@ -16,8 +16,8 @@ type Props = {
export const ProfileNavbar: React.FC<Props> = (props) => { export const ProfileNavbar: React.FC<Props> = (props) => {
const { isAuthorized, showProfileIssuesFilter } = props; const { isAuthorized, showProfileIssuesFilter } = props;
const router = useRouter(); const { workspaceSlug, userId } = useParams();
const { workspaceSlug, userId } = router.query; const pathname = usePathname();
const tabsList = isAuthorized ? [...PROFILE_VIEWER_TAB, ...PROFILE_ADMINS_TAB] : PROFILE_VIEWER_TAB; const tabsList = isAuthorized ? [...PROFILE_VIEWER_TAB, ...PROFILE_ADMINS_TAB] : PROFILE_VIEWER_TAB;
@ -28,7 +28,7 @@ export const ProfileNavbar: React.FC<Props> = (props) => {
<Link key={tab.route} href={`/${workspaceSlug}/profile/${userId}/${tab.route}`}> <Link key={tab.route} href={`/${workspaceSlug}/profile/${userId}/${tab.route}`}>
<span <span
className={`flex whitespace-nowrap border-b-2 p-4 text-sm font-medium outline-none ${ className={`flex whitespace-nowrap border-b-2 p-4 text-sm font-medium outline-none ${
router.pathname === tab.selected pathname === `/${workspaceSlug}/profile/${userId}${tab.selected}`
? "border-custom-primary-100 text-custom-primary-100" ? "border-custom-primary-100 text-custom-primary-100"
: "border-transparent" : "border-transparent"
}`} }`}

View File

@ -1,12 +1,11 @@
import { ReactElement } from "react"; "use client";
import { useRouter } from "next/router";
import { useParams } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// types
import { IUserStateDistribution, TStateGroups } from "@plane/types"; import { IUserStateDistribution, TStateGroups } from "@plane/types";
// services
// layouts
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { UserProfileHeader } from "@/components/headers";
import { import {
ProfileActivity, ProfileActivity,
ProfilePriorityDistribution, ProfilePriorityDistribution,
@ -14,21 +13,17 @@ import {
ProfileStats, ProfileStats,
ProfileWorkload, ProfileWorkload,
} from "@/components/profile"; } from "@/components/profile";
// types
// constants // constants
import { USER_PROFILE_DATA } from "@/constants/fetch-keys"; import { USER_PROFILE_DATA } from "@/constants/fetch-keys";
import { GROUP_CHOICES } from "@/constants/project"; import { GROUP_CHOICES } from "@/constants/project";
import { AppLayout } from "@/layouts/app-layout"; // services
import { ProfileAuthWrapper } from "@/layouts/user-profile-layout";
import { NextPageWithLayout } from "@/lib/types";
import { UserService } from "@/services/user.service"; import { UserService } from "@/services/user.service";
// services // services
const userService = new UserService(); const userService = new UserService();
const ProfileOverviewPage: NextPageWithLayout = () => { const ProfileOverviewPage = () => {
const router = useRouter(); const { workspaceSlug, userId } = useParams();
const { workspaceSlug, userId } = router.query;
const { data: userProfile } = useSWR( const { data: userProfile } = useSWR(
workspaceSlug && userId ? USER_PROFILE_DATA(workspaceSlug.toString(), userId.toString()) : null, workspaceSlug && userId ? USER_PROFILE_DATA(workspaceSlug.toString(), userId.toString()) : null,
@ -58,12 +53,4 @@ const ProfileOverviewPage: NextPageWithLayout = () => {
); );
}; };
ProfileOverviewPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<UserProfileHeader type="Summary" />}>
<ProfileAuthWrapper>{page}</ProfileAuthWrapper>
</AppLayout>
);
};
export default ProfileOverviewPage; export default ProfileOverviewPage;

View File

@ -0,0 +1,16 @@
"use client";
// store
import { observer } from "mobx-react-lite";
// components
import { PageHead } from "@/components/core";
import { ProfileIssuesPage } from "@/components/profile/profile-issues";
const ProfileSubscribedIssuesPage = () => (
<>
<PageHead title="Profile - Subscribed" />
<ProfileIssuesPage type="subscribed" />
</>
);
export default observer(ProfileSubscribedIssuesPage);

View File

@ -1,21 +1,16 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ArchivedCycleLayoutRoot, ArchivedCyclesHeader } from "@/components/cycles"; import { ArchivedCycleLayoutRoot, ArchivedCyclesHeader } from "@/components/cycles";
import { ProjectArchivesHeader } from "@/components/headers";
// hooks // hooks
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const ProjectArchivedCyclesPage: NextPageWithLayout = observer(() => { const ProjectArchivedCyclesPage = observer(() => {
// router // router
const router = useRouter(); const { projectId } = useParams();
const { projectId } = router.query;
// store hooks // store hooks
const { getProjectById } = useProject(); const { getProjectById } = useProject();
// derived values // derived values
@ -33,12 +28,4 @@ const ProjectArchivedCyclesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectArchivedCyclesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectArchivesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectArchivedCyclesPage; export default ProjectArchivedCyclesPage;

View File

@ -1,6 +1,8 @@
import { useState, ReactElement } from "react"; "use client";
import { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// icons // icons
import { ArchiveRestoreIcon } from "lucide-react"; import { ArchiveRestoreIcon } from "lucide-react";
@ -8,22 +10,17 @@ import { ArchiveRestoreIcon } from "lucide-react";
import { ArchiveIcon, Button, Loader, TOAST_TYPE, setToast } from "@plane/ui"; import { ArchiveIcon, Button, Loader, TOAST_TYPE, setToast } from "@plane/ui";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectArchivedIssueDetailsHeader } from "@/components/headers";
import { IssueDetailRoot } from "@/components/issues"; import { IssueDetailRoot } from "@/components/issues";
// constants // constants
import { EIssuesStoreType } from "@/constants/issue"; import { EIssuesStoreType } from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project"; import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useIssueDetail, useIssues, useProject, useUser } from "@/hooks/store"; import { useIssueDetail, useIssues, useProject, useUser } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const ArchivedIssueDetailsPage: NextPageWithLayout = observer(() => { const ArchivedIssueDetailsPage = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, archivedIssueId } = router.query; const { workspaceSlug, projectId, archivedIssueId } = useParams();
// states // states
const [isRestoring, setIsRestoring] = useState(false); const [isRestoring, setIsRestoring] = useState(false);
// hooks // hooks
@ -137,12 +134,4 @@ const ArchivedIssueDetailsPage: NextPageWithLayout = observer(() => {
); );
}); });
ArchivedIssueDetailsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectArchivedIssueDetailsHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ArchivedIssueDetailsPage; export default ArchivedIssueDetailsPage;

View File

@ -1,21 +1,16 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectArchivesHeader } from "@/components/headers";
import { ArchivedIssueLayoutRoot, ArchivedIssuesHeader } from "@/components/issues"; import { ArchivedIssueLayoutRoot, ArchivedIssuesHeader } from "@/components/issues";
// hooks // hooks
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const ProjectArchivedIssuesPage: NextPageWithLayout = observer(() => { const ProjectArchivedIssuesPage = observer(() => {
// router // router
const router = useRouter(); const { projectId } = useParams();
const { projectId } = router.query;
// store hooks // store hooks
const { getProjectById } = useProject(); const { getProjectById } = useProject();
// derived values // derived values
@ -33,12 +28,4 @@ const ProjectArchivedIssuesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectArchivedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectArchivesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectArchivedIssuesPage; export default ProjectArchivedIssuesPage;

View File

@ -1,21 +1,16 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectArchivesHeader } from "@/components/headers";
import { ArchivedModuleLayoutRoot, ArchivedModulesHeader } from "@/components/modules"; import { ArchivedModuleLayoutRoot, ArchivedModulesHeader } from "@/components/modules";
// hooks // hooks
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const ProjectArchivedModulesPage: NextPageWithLayout = observer(() => { const ProjectArchivedModulesPage = observer(() => {
// router // router
const router = useRouter(); const { projectId } = useParams();
const { projectId } = router.query;
// store hooks // store hooks
const { getProjectById } = useProject(); const { getProjectById } = useProject();
// derived values // derived values
@ -33,12 +28,4 @@ const ProjectArchivedModulesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectArchivedModulesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectArchivesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectArchivedModulesPage; export default ProjectArchivedModulesPage;

View File

@ -1,29 +1,23 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// hooks // components
import { EmptyState } from "@/components/common"; import { EmptyState } from "@/components/common";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { CycleDetailsSidebar } from "@/components/cycles"; import { CycleDetailsSidebar } from "@/components/cycles";
import { CycleMobileHeader } from "@/components/cycles/cycle-mobile-header";
import { CycleIssuesHeader } from "@/components/headers";
import { CycleLayoutRoot } from "@/components/issues/issue-layouts"; import { CycleLayoutRoot } from "@/components/issues/issue-layouts";
// hooks
import { useCycle, useProject } from "@/hooks/store"; import { useCycle, useProject } from "@/hooks/store";
import useLocalStorage from "@/hooks/use-local-storage"; import useLocalStorage from "@/hooks/use-local-storage";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// components
// ui
// assets // assets
import { NextPageWithLayout } from "@/lib/types";
import emptyCycle from "public/empty-state/cycle.svg"; import emptyCycle from "public/empty-state/cycle.svg";
// types
const CycleDetailPage: NextPageWithLayout = observer(() => { const CycleDetailPage = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId } = router.query; const { workspaceSlug, projectId, cycleId } = useParams();
// store hooks // store hooks
const { fetchCycleDetails, getCycleById } = useCycle(); const { fetchCycleDetails, getCycleById } = useCycle();
const { getProjectById } = useProject(); const { getProjectById } = useProject();
@ -84,12 +78,4 @@ const CycleDetailPage: NextPageWithLayout = observer(() => {
); );
}); });
CycleDetailPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<CycleIssuesHeader />} mobileHeader={<CycleMobileHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default CycleDetailPage; export default CycleDetailPage;

View File

@ -1,14 +1,14 @@
import { useState, ReactElement } from "react"; "use client";
import { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// types // types
import { TCycleFilters } from "@plane/types"; import { TCycleFilters } from "@plane/types";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { CyclesView, CycleCreateUpdateModal, CycleAppliedFiltersList } from "@/components/cycles"; import { CyclesView, CycleCreateUpdateModal, CycleAppliedFiltersList } from "@/components/cycles";
import CyclesListMobileHeader from "@/components/cycles/cycles-list-mobile-header";
import { EmptyState } from "@/components/empty-state"; import { EmptyState } from "@/components/empty-state";
import { CyclesHeader } from "@/components/headers";
import { CycleModuleListLayout } from "@/components/ui"; import { CycleModuleListLayout } from "@/components/ui";
// constants // constants
import { EmptyStateType } from "@/constants/empty-state"; import { EmptyStateType } from "@/constants/empty-state";
@ -16,12 +16,8 @@ import { EmptyStateType } from "@/constants/empty-state";
import { calculateTotalFilters } from "@/helpers/filter.helper"; import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks // hooks
import { useEventTracker, useCycle, useProject, useCycleFilter } from "@/hooks/store"; import { useEventTracker, useCycle, useProject, useCycleFilter } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const ProjectCyclesPage: NextPageWithLayout = observer(() => { const ProjectCyclesPage = observer(() => {
// states // states
const [createModal, setCreateModal] = useState(false); const [createModal, setCreateModal] = useState(false);
// store hooks // store hooks
@ -29,8 +25,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
const { currentProjectCycleIds, loader } = useCycle(); const { currentProjectCycleIds, loader } = useCycle();
const { getProjectById, currentProjectDetails } = useProject(); const { getProjectById, currentProjectDetails } = useProject();
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// cycle filters hook // cycle filters hook
const { clearAllFilters, currentProjectFilters, updateFilters } = useCycleFilter(); const { clearAllFilters, currentProjectFilters, updateFilters } = useCycleFilter();
// derived values // derived values
@ -103,12 +98,4 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectCyclesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<CyclesHeader />} mobileHeader={<CyclesListMobileHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectCyclesPage; export default ProjectCyclesPage;

View File

@ -1,21 +1,17 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import { X, PenSquare } from "lucide-react"; import { X, PenSquare } from "lucide-react";
// layouts
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectDraftIssueHeader } from "@/components/headers";
import { DraftIssueLayoutRoot } from "@/components/issues/issue-layouts/roots/draft-issue-layout-root"; import { DraftIssueLayoutRoot } from "@/components/issues/issue-layouts/roots/draft-issue-layout-root";
// types
// hooks // hooks
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
import { NextPageWithLayout } from "@/lib/types";
const ProjectDraftIssuesPage: NextPageWithLayout = observer(() => { const ProjectDraftIssuesPage = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = useParams();
// store // store
const { getProjectById } = useProject(); const { getProjectById } = useProject();
// derived values // derived values
@ -43,12 +39,4 @@ const ProjectDraftIssuesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectDraftIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectDraftIssueHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectDraftIssuesPage; export default ProjectDraftIssuesPage;

View File

@ -0,0 +1,63 @@
"use client";
import { observer } from "mobx-react";
import { useParams, useSearchParams } from "next/navigation";
// components
import { PageHead } from "@/components/core";
import { EmptyState } from "@/components/empty-state";
import { InboxIssueRoot } from "@/components/inbox";
// constants
import { EmptyStateType } from "@/constants/empty-state";
// helpers
import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper";
// hooks
import { useProject } from "@/hooks/store";
const ProjectInboxPage = observer(() => {
/// router
const { workspaceSlug, projectId } = useParams();
const searchParams = useSearchParams();
const navigationTab = searchParams.get("currentTab");
const inboxIssueId = searchParams.get("inboxIssueId");
// hooks
const { currentProjectDetails } = useProject();
// No access to inbox
if (currentProjectDetails?.inbox_view === false)
return (
<div className="flex items-center justify-center h-full w-full">
<EmptyState
type={EmptyStateType.DISABLED_PROJECT_INBOX}
primaryButtonLink={`/${workspaceSlug}/projects/${projectId}/settings/features`}
/>
</div>
);
// derived values
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Inbox` : "Plane - Inbox";
const currentNavigationTab = navigationTab
? navigationTab === "open"
? EInboxIssueCurrentTab.OPEN
: EInboxIssueCurrentTab.CLOSED
: undefined;
if (!workspaceSlug || !projectId) return <></>;
return (
<div className="flex h-full flex-col">
<PageHead title={pageTitle} />
<div className="w-full h-full overflow-hidden">
<InboxIssueRoot
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
inboxIssueId={inboxIssueId?.toString() || undefined}
inboxAccessible={currentProjectDetails?.inbox_view || false}
navigationTab={currentNavigationTab}
/>
</div>
</div>
);
});
export default ProjectInboxPage;

View File

@ -1,6 +1,8 @@
import React, { ReactElement, useEffect } from "react"; "use client";
import React, { useEffect } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import useSWR from "swr"; import useSWR from "swr";
// ui // ui
@ -8,22 +10,17 @@ import { Loader } from "@plane/ui";
// components // components
import { EmptyState } from "@/components/common"; import { EmptyState } from "@/components/common";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectIssueDetailsHeader } from "@/components/headers";
import { IssueDetailRoot } from "@/components/issues"; import { IssueDetailRoot } from "@/components/issues";
// hooks // hooks
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store"; import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
// assets // assets
import emptyIssueDark from "@/public/empty-state/search/issues-dark.webp"; import emptyIssueDark from "@/public/empty-state/search/issues-dark.webp";
import emptyIssueLight from "@/public/empty-state/search/issues-light.webp"; import emptyIssueLight from "@/public/empty-state/search/issues-light.webp";
const IssueDetailsPage: NextPageWithLayout = observer(() => { const IssueDetailsPage = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = useParams();
// hooks // hooks
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
// store hooks // store hooks
@ -108,12 +105,4 @@ const IssueDetailsPage: NextPageWithLayout = observer(() => {
); );
}); });
IssueDetailsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectIssueDetailsHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default IssueDetailsPage; export default IssueDetailsPage;

View File

@ -1,22 +1,16 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Head from "next/head"; import Head from "next/head";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectIssuesHeader } from "@/components/headers";
import { ProjectLayoutRoot } from "@/components/issues"; import { ProjectLayoutRoot } from "@/components/issues";
// types
import { IssuesMobileHeader } from "@/components/issues/issues-mobile-header";
import { useProject } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
import { NextPageWithLayout } from "@/lib/types";
// layouts
// hooks // hooks
import { useProject } from "@/hooks/store";
const ProjectIssuesPage: NextPageWithLayout = observer(() => { const ProjectIssuesPage = observer(() => {
const router = useRouter(); const { projectId } = useParams();
const { projectId } = router.query;
// store // store
const { getProjectById } = useProject(); const { getProjectById } = useProject();
@ -41,12 +35,4 @@ const ProjectIssuesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectIssuesHeader />} mobileHeader={<IssuesMobileHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectIssuesPage; export default ProjectIssuesPage;

View File

@ -0,0 +1,13 @@
"use client";
import { ReactNode } from "react"
// layouts
import { ProjectAuthWrapper } from "@/layouts/auth-layout"
const ProjectLayout = ({ children }: { children: ReactNode }) => (
<ProjectAuthWrapper>
{children}
</ProjectAuthWrapper>
);
export default ProjectLayout;

View File

@ -1,28 +1,23 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// hooks // components
import { EmptyState } from "@/components/common"; import { EmptyState } from "@/components/common";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ModuleIssuesHeader } from "@/components/headers";
import { ModuleLayoutRoot } from "@/components/issues"; import { ModuleLayoutRoot } from "@/components/issues";
import { ModuleDetailsSidebar } from "@/components/modules"; import { ModuleDetailsSidebar } from "@/components/modules";
import { ModuleMobileHeader } from "@/components/modules/module-mobile-header"; // hooks
import { useModule, useProject } from "@/hooks/store"; import { useModule, useProject } from "@/hooks/store";
import useLocalStorage from "@/hooks/use-local-storage"; import useLocalStorage from "@/hooks/use-local-storage";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// components
// assets // assets
import { NextPageWithLayout } from "@/lib/types";
import emptyModule from "public/empty-state/module.svg"; import emptyModule from "public/empty-state/module.svg";
// types
const ModuleIssuesPage: NextPageWithLayout = observer(() => { const ModuleIssuesPage = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query; const { workspaceSlug, projectId, moduleId } = useParams();
// store hooks // store hooks
const { fetchModuleDetails, getModuleById } = useModule(); const { fetchModuleDetails, getModuleById } = useModule();
const { getProjectById } = useProject(); const { getProjectById } = useProject();
@ -82,12 +77,4 @@ const ModuleIssuesPage: NextPageWithLayout = observer(() => {
); );
}); });
ModuleIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ModuleIssuesHeader />} mobileHeader={<ModuleMobileHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ModuleIssuesPage; export default ModuleIssuesPage;

View File

@ -1,28 +1,23 @@
import { ReactElement, useCallback } from "react"; "use client";
import { useCallback } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// types // types
import { TModuleFilters } from "@plane/types"; import { TModuleFilters } from "@plane/types";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { EmptyState } from "@/components/empty-state"; import { EmptyState } from "@/components/empty-state";
import { ModulesListHeader } from "@/components/headers";
import { ModuleAppliedFiltersList, ModulesListView } from "@/components/modules"; import { ModuleAppliedFiltersList, ModulesListView } from "@/components/modules";
import ModulesListMobileHeader from "@/components/modules/moduels-list-mobile-header";
// constants // constants
import { EmptyStateType } from "@/constants/empty-state"; import { EmptyStateType } from "@/constants/empty-state";
// helpers // helpers
import { calculateTotalFilters } from "@/helpers/filter.helper"; import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks // hooks
import { useModuleFilter, useProject } from "@/hooks/store"; import { useModuleFilter, useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const ProjectModulesPage: NextPageWithLayout = observer(() => { const ProjectModulesPage = observer(() => {
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store // store
const { getProjectById, currentProjectDetails } = useProject(); const { getProjectById, currentProjectDetails } = useProject();
const { currentProjectFilters, currentProjectDisplayFilters, clearAllFilters, updateFilters, updateDisplayFilters } = const { currentProjectFilters, currentProjectDisplayFilters, clearAllFilters, updateFilters, updateDisplayFilters } =
@ -82,12 +77,4 @@ const ProjectModulesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectModulesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ModulesListHeader />} mobileHeader={<ModulesListMobileHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectModulesPage; export default ProjectModulesPage;

View File

@ -1,7 +1,9 @@
import { ReactElement, useRef, useState } from "react"; "use client";
import { useRef, useState } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// document-editor // document-editor
import { EditorRefApi, useEditorMarkings } from "@plane/document-editor"; import { EditorRefApi, useEditorMarkings } from "@plane/document-editor";
@ -12,19 +14,14 @@ import { TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
// components // components
import { LogoSpinner } from "@/components/common"; import { LogoSpinner } from "@/components/common";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { PageDetailsHeader } from "@/components/headers";
import { IssuePeekOverview } from "@/components/issues"; import { IssuePeekOverview } from "@/components/issues";
import { PageEditorBody, PageEditorHeaderRoot } from "@/components/pages"; import { PageEditorBody, PageEditorHeaderRoot } from "@/components/pages";
// helpers // helpers
import { cn } from "@/helpers/common.helper"; import { cn } from "@/helpers/common.helper";
// hooks // hooks
import { usePage, useProjectPages } from "@/hooks/store"; import { usePage, useProjectPages } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// lib
import { NextPageWithLayout } from "@/lib/types";
const PageDetailsPage: NextPageWithLayout = observer(() => { const PageDetailsPage = observer(() => {
// states // states
const [sidePeekVisible, setSidePeekVisible] = useState(window.innerWidth >= 768 ? true : false); const [sidePeekVisible, setSidePeekVisible] = useState(window.innerWidth >= 768 ? true : false);
const [editorReady, setEditorReady] = useState(false); const [editorReady, setEditorReady] = useState(false);
@ -34,7 +31,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
const readOnlyEditorRef = useRef<EditorRefApi>(null); const readOnlyEditorRef = useRef<EditorRefApi>(null);
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, pageId } = router.query; const { workspaceSlug, projectId, pageId } = useParams();
// store hooks // store hooks
const { createPage, getPageById } = useProjectPages(); const { createPage, getPageById } = useProjectPages();
const page = usePage(pageId?.toString() ?? ""); const page = usePage(pageId?.toString() ?? "");
@ -131,12 +128,4 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
); );
}); });
PageDetailsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<PageDetailsHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default PageDetailsPage; export default PageDetailsPage;

View File

@ -1,23 +1,19 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useSearchParams } from "next/navigation";
// types // types
import { TPageNavigationTabs } from "@plane/types"; import { TPageNavigationTabs } from "@plane/types";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { PagesHeader } from "@/components/headers";
import { PagesListRoot, PagesListView } from "@/components/pages"; import { PagesListRoot, PagesListView } from "@/components/pages";
// hooks // hooks
import { useAppRouter, useProject } from "@/hooks/store"; import { useAppRouter, useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// lib
import { NextPageWithLayout } from "@/lib/types";
const ProjectPagesPage: NextPageWithLayout = observer(() => { const ProjectPagesPage = observer(() => {
// router // router
const router = useRouter(); const searchParams = useSearchParams();
const { type } = router.query; const type = searchParams.get("type");
// store hooks // store hooks
const { workspaceSlug, projectId } = useAppRouter(); const { workspaceSlug, projectId } = useAppRouter();
const { getProjectById } = useProject(); const { getProjectById } = useProject();
@ -51,12 +47,4 @@ const ProjectPagesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectPagesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<PagesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectPagesPage; export default ProjectPagesPage;

View File

@ -1,30 +1,22 @@
import React, { ReactElement } from "react"; "use client";
import { observer } from "mobx-react";
import { useRouter } from "next/router";
import { IProject } from "@plane/types";
// hooks
import { TOAST_TYPE, setToast } from "@plane/ui";
import { AutoArchiveAutomation, AutoCloseAutomation } from "@/components/automation";
// layouts
// ui
// components
import { PageHead } from "@/components/core";
import { ProjectSettingHeader } from "@/components/headers";
import { EUserProjectRoles } from "@/constants/project";
import { useProject, useUser } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
// layouts
import { ProjectSettingLayout } from "@/layouts/settings-layout";
// hooks
// components
// types
import { NextPageWithLayout } from "@/lib/types";
// constants
const AutomationSettingsPage: NextPageWithLayout = observer(() => { import React from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { IProject } from "@plane/types";
// ui
import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { AutoArchiveAutomation, AutoCloseAutomation } from "@/components/automation";
import { PageHead } from "@/components/core";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useProject, useUser } from "@/hooks/store";
const AutomationSettingsPage = observer(() => {
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { const {
membership: { currentProjectRole }, membership: { currentProjectRole },
@ -61,12 +53,4 @@ const AutomationSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
AutomationSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default AutomationSettingsPage; export default AutomationSettingsPage;

View File

@ -1,23 +1,17 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { EstimateRoot } from "@/components/estimates"; import { EstimateRoot } from "@/components/estimates";
import { ProjectSettingHeader } from "@/components/headers";
// constants // constants
import { EUserProjectRoles } from "@/constants/project"; import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useUser, useProject } from "@/hooks/store"; import { useUser, useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
import { ProjectSettingLayout } from "@/layouts/settings-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const EstimatesSettingsPage: NextPageWithLayout = observer(() => { const EstimatesSettingsPage = observer(() => {
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
const { const {
membership: { currentProjectRole }, membership: { currentProjectRole },
} = useUser(); } = useUser();
@ -38,12 +32,4 @@ const EstimatesSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
EstimatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default EstimatesSettingsPage; export default EstimatesSettingsPage;

View File

@ -1,24 +1,18 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react";
import { useRouter } from "next/router";
import useSWR from "swr";
// hooks
import { PageHead } from "@/components/core";
import { ProjectSettingHeader } from "@/components/headers";
import { ProjectFeaturesList } from "@/components/project";
import { EUserProjectRoles } from "@/constants/project";
import { useProject, useUser } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
import { ProjectSettingLayout } from "@/layouts/settings-layout";
// components
// types
import { NextPageWithLayout } from "@/lib/types";
// constants
const FeaturesSettingsPage: NextPageWithLayout = observer(() => { import { observer } from "mobx-react";
const router = useRouter(); import { useParams } from "next/navigation";
const { workspaceSlug, projectId } = router.query; import useSWR from "swr";
// components
import { PageHead } from "@/components/core";
import { ProjectFeaturesList } from "@/components/project";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useProject, useUser } from "@/hooks/store";
const FeaturesSettingsPage = observer(() => {
const { workspaceSlug, projectId } = useParams();
// store // store
const { const {
membership: { fetchUserProjectInfo }, membership: { fetchUserProjectInfo },
@ -52,12 +46,4 @@ const FeaturesSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
FeaturesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default FeaturesSettingsPage; export default FeaturesSettingsPage;

View File

@ -1,20 +1,16 @@
import { ReactElement, useEffect, useRef } from "react"; "use client";
import { useEffect, useRef } from "react";
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element"; import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// layouts
import { PageHead } from "@/components/core";
import { ProjectSettingHeader } from "@/components/headers";
import { ProjectSettingsLabelList } from "@/components/labels";
import { useProject } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
import { ProjectSettingLayout } from "@/layouts/settings-layout";
// components // components
// types import { PageHead } from "@/components/core";
import { NextPageWithLayout } from "@/lib/types"; import { ProjectSettingsLabelList } from "@/components/labels";
// hooks // hooks
import { useProject } from "@/hooks/store";
const LabelsSettingsPage: NextPageWithLayout = observer(() => { const LabelsSettingsPage = observer(() => {
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Labels` : undefined; const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Labels` : undefined;
@ -43,12 +39,4 @@ const LabelsSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
LabelsSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout withProjectWrapper header={<ProjectSettingHeader />}>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default LabelsSettingsPage; export default LabelsSettingsPage;

View File

@ -1,26 +1,28 @@
"use client";
import { FC, ReactNode } from "react"; import { FC, ReactNode } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
// hooks
// components
import { Button, LayersIcon } from "@plane/ui";
import { NotAuthorizedView } from "@/components/auth-screens";
// ui // ui
import { Button, LayersIcon } from "@plane/ui";
// components
import { NotAuthorizedView } from "@/components/auth-screens";
// constants // constants
import { EUserProjectRoles } from "@/constants/project"; import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useUser } from "@/hooks/store"; import { useUser } from "@/hooks/store";
import { ProjectSettingsSidebar } from "./sidebar"; // local components
import ProjectSettingsSidebar from "./sidebar";
export interface IProjectSettingLayout { export interface IProjectSettingLayout {
children: ReactNode; children: ReactNode;
} }
export const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props) => { const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props) => {
const { children } = props; const { children } = props;
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { const {
membership: { currentProjectRole }, membership: { currentProjectRole },
@ -51,3 +53,5 @@ export const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props)
</div> </div>
); );
}); });
export default ProjectSettingLayout;

View File

@ -1,18 +1,13 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// layouts
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectSettingHeader } from "@/components/headers";
import { ProjectMemberList, ProjectSettingsMemberDefaults } from "@/components/project"; import { ProjectMemberList, ProjectSettingsMemberDefaults } from "@/components/project";
// types
// hooks // hooks
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
import { ProjectSettingLayout } from "@/layouts/settings-layout";
import { NextPageWithLayout } from "@/lib/types";
const MembersSettingsPage: NextPageWithLayout = observer(() => { const MembersSettingsPage = observer(() => {
// store // store
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
// derived values // derived values
@ -29,12 +24,4 @@ const MembersSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
MembersSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default MembersSettingsPage; export default MembersSettingsPage;

View File

@ -1,10 +1,11 @@
import { useState, ReactElement } from "react"; "use client";
import { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// components // components
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectSettingHeader } from "@/components/headers";
import { import {
ArchiveRestoreProjectModal, ArchiveRestoreProjectModal,
ArchiveProjectSelection, ArchiveProjectSelection,
@ -15,19 +16,13 @@ import {
} from "@/components/project"; } from "@/components/project";
// hooks // hooks
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
import { ProjectSettingLayout } from "@/layouts/settings-layout";
// types
import { NextPageWithLayout } from "@/lib/types";
const GeneralSettingsPage: NextPageWithLayout = observer(() => { const GeneralSettingsPage = observer(() => {
// states // states
const [selectProject, setSelectedProject] = useState<string | null>(null); const [selectProject, setSelectedProject] = useState<string | null>(null);
const [archiveProject, setArchiveProject] = useState<boolean>(false); const [archiveProject, setArchiveProject] = useState<boolean>(false);
// router // router
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { currentProjectDetails, fetchProjectDetails } = useProject(); const { currentProjectDetails, fetchProjectDetails } = useProject();
// api call to fetch project details // api call to fetch project details
@ -91,12 +86,4 @@ const GeneralSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
GeneralSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default GeneralSettingsPage; export default GeneralSettingsPage;

View File

@ -1,16 +1,16 @@
import React from "react"; import React from "react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useParams, usePathname } from "next/navigation";
// ui // ui
import { Loader } from "@plane/ui"; import { Loader } from "@plane/ui";
// hooks
import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
import { useUser } from "@/hooks/store";
// constants // constants
import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
// hooks
import { useUser } from "@/hooks/store";
export const ProjectSettingsSidebar = () => { const ProjectSettingsSidebar = () => {
const router = useRouter(); const { workspaceSlug, projectId } = useParams();
const { workspaceSlug, projectId } = router.query; const pathname = usePathname();
// mobx store // mobx store
const { const {
membership: { currentProjectRole }, membership: { currentProjectRole },
@ -43,11 +43,10 @@ export const ProjectSettingsSidebar = () => {
projectMemberInfo >= link.access && ( projectMemberInfo >= link.access && (
<Link key={link.key} href={`/${workspaceSlug}/projects/${projectId}${link.href}`}> <Link key={link.key} href={`/${workspaceSlug}/projects/${projectId}${link.href}`}>
<div <div
className={`rounded-md px-4 py-2 text-sm font-medium ${ className={`rounded-md px-4 py-2 text-sm font-medium ${link.highlight(pathname, `/${workspaceSlug}/projects/${projectId}`)
link.highlight(router.asPath, `/${workspaceSlug}/projects/${projectId}`)
? "bg-custom-primary-100/10 text-custom-primary-100" ? "bg-custom-primary-100/10 text-custom-primary-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80" : "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
}`} }`}
> >
{link.label} {link.label}
</div> </div>
@ -59,3 +58,5 @@ export const ProjectSettingsSidebar = () => {
</div> </div>
); );
}; };
export default ProjectSettingsSidebar;

View File

@ -1,18 +1,13 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react";
// layout
import { PageHead } from "@/components/core";
import { ProjectSettingHeader } from "@/components/headers";
import { ProjectSettingStateList } from "@/components/states";
import { useProject } from "@/hooks/store";
import { AppLayout } from "@/layouts/app-layout";
import { ProjectSettingLayout } from "@/layouts/settings-layout";
// components
// types
import { NextPageWithLayout } from "@/lib/types";
// hook
const StatesSettingsPage: NextPageWithLayout = observer(() => { import { observer } from "mobx-react";
// components
import { PageHead } from "@/components/core";
import { ProjectSettingStateList } from "@/components/states";
// hook
import { useProject } from "@/hooks/store";
const StatesSettingsPage = observer(() => {
// store // store
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
// derived values // derived values
@ -30,12 +25,4 @@ const StatesSettingsPage: NextPageWithLayout = observer(() => {
); );
}); });
StatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout withProjectWrapper header={<ProjectSettingHeader />}>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default StatesSettingsPage; export default StatesSettingsPage;

View File

@ -1,26 +1,21 @@
import { ReactElement } from "react"; "use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/router"; import { useParams, useRouter } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
// hooks // components
import { EmptyState } from "@/components/common"; import { EmptyState } from "@/components/common";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
import { ProjectViewIssuesHeader } from "@/components/headers";
import { ProjectViewLayoutRoot } from "@/components/issues"; import { ProjectViewLayoutRoot } from "@/components/issues";
// hooks
import { useProject, useProjectView } from "@/hooks/store"; import { useProject, useProjectView } from "@/hooks/store";
// layouts
import { AppLayout } from "@/layouts/app-layout";
// components
// ui
// assets // assets
import { NextPageWithLayout } from "@/lib/types";
import emptyView from "public/empty-state/view.svg"; import emptyView from "public/empty-state/view.svg";
// types
const ProjectViewIssuesPage: NextPageWithLayout = observer(() => { const ProjectViewIssuesPage = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, viewId } = router.query; const { workspaceSlug, projectId, viewId } = useParams();
// store hooks // store hooks
const { fetchViewDetails, getViewById } = useProjectView(); const { fetchViewDetails, getViewById } = useProjectView();
const { getProjectById } = useProject(); const { getProjectById } = useProject();
@ -58,12 +53,4 @@ const ProjectViewIssuesPage: NextPageWithLayout = observer(() => {
); );
}); });
ProjectViewIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectViewIssuesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectViewIssuesPage; export default ProjectViewIssuesPage;

Some files were not shown because too many files have changed in this diff Show More