diff --git a/web/components/profile/preferences/preferences-mobile-header.tsx b/web/components/profile/preferences/preferences-mobile-header.tsx new file mode 100644 index 00000000000..41ad464aeaa --- /dev/null +++ b/web/components/profile/preferences/preferences-mobile-header.tsx @@ -0,0 +1,38 @@ +import Link from "next/link"; +import router from "next/router"; +// helpers +import { cn } from "@/helpers/common.helper"; + +export const PreferencesMobileHeader = () => { + const profilePreferenceLinks: Array<{ + label: string; + href: string; + }> = [ + { + label: "Theme", + href: `/profile/preferences/theme`, + }, + { + label: "Email", + href: `/profile/preferences/email`, + }, + ]; + + return ( +
+ {profilePreferenceLinks.map((link, index) => ( + console.log(router.asPath)} + className={cn( + "flex justify-around py-2 w-full", + router.asPath.includes(link.label.toLowerCase()) ? "border-b-2 border-custom-primary-100" : "" + )} + > +
{link.label}
+ + ))} +
+ ); +}; diff --git a/web/components/profile/profile-issues-mobile-header.tsx b/web/components/profile/profile-issues-mobile-header.tsx new file mode 100644 index 00000000000..6880f6b4ba7 --- /dev/null +++ b/web/components/profile/profile-issues-mobile-header.tsx @@ -0,0 +1,177 @@ +import { useCallback } from "react"; +import { observer } from "mobx-react"; +import { useRouter } from "next/router"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types"; +// ui +import { CustomMenu } from "@plane/ui"; +// components +import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues"; +// constants +import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue"; +// hooks +import { useIssues, useLabel } from "@/hooks/store"; + + +const ProfileIssuesMobileHeader = observer(() => { + // router + const router = useRouter(); + const { workspaceSlug, userId } = router.query; + // store hook + const { + issuesFilter: { issueFilters, updateFilters }, + } = useIssues(EIssuesStoreType.PROFILE); + + const { workspaceLabels } = useLabel(); + // derived values + const states = undefined; + // const members = undefined; + // const activeLayout = issueFilters?.displayFilters?.layout; + // const states = undefined; + const members = undefined; + const activeLayout = issueFilters?.displayFilters?.layout; + + const handleLayoutChange = useCallback( + (layout: TIssueLayouts) => { + if (!workspaceSlug || !userId) return; + updateFilters( + workspaceSlug.toString(), + undefined, + EIssueFilterType.DISPLAY_FILTERS, + { layout: layout }, + userId.toString() + ); + }, + [workspaceSlug, updateFilters, userId] + ); + + const handleFiltersUpdate = useCallback( + (key: keyof IIssueFilterOptions, value: string | string[]) => { + if (!workspaceSlug || !userId) return; + const newValues = issueFilters?.filters?.[key] ?? []; + + if (Array.isArray(value)) { + value.forEach((val) => { + if (!newValues.includes(val)) newValues.push(val); + }); + } else { + if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); + else newValues.push(value); + } + + updateFilters( + workspaceSlug.toString(), + undefined, + EIssueFilterType.FILTERS, + { [key]: newValues }, + userId.toString() + ); + }, + [workspaceSlug, issueFilters, updateFilters, userId] + ); + + const handleDisplayFilters = useCallback( + (updatedDisplayFilter: Partial) => { + if (!workspaceSlug || !userId) return; + updateFilters( + workspaceSlug.toString(), + undefined, + EIssueFilterType.DISPLAY_FILTERS, + updatedDisplayFilter, + userId.toString() + ); + }, + [workspaceSlug, updateFilters, userId] + ); + + const handleDisplayProperties = useCallback( + (property: Partial) => { + if (!workspaceSlug || !userId) return; + updateFilters( + workspaceSlug.toString(), + undefined, + EIssueFilterType.DISPLAY_PROPERTIES, + property, + userId.toString() + ); + }, + [workspaceSlug, updateFilters, userId] + ); + return ( +
+ Layout} + customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm" + closeOnSelect + > + {ISSUE_LAYOUTS.map((layout, index) => { + if (layout.key === "spreadsheet" || layout.key === "gantt_chart" || layout.key === "calendar") return; + return ( + { + handleLayoutChange(ISSUE_LAYOUTS[index].key); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ); + })} +
+
+ + Filters + + + } + > + + +
+
+ + Display + + + } + > + + +
+
+ ); +}); + +export default ProfileIssuesMobileHeader; diff --git a/web/layouts/settings-layout/profile/preferences/layout.tsx b/web/layouts/settings-layout/profile/preferences/layout.tsx index f7fff2ef136..4219696e2f8 100644 --- a/web/layouts/settings-layout/profile/preferences/layout.tsx +++ b/web/layouts/settings-layout/profile/preferences/layout.tsx @@ -1,10 +1,7 @@ import { FC, ReactNode } from "react"; // layout -import Link from "next/link"; -import { useRouter } from "next/router"; -import { ChevronDown } from "lucide-react"; -import { CustomMenu } from "@plane/ui"; import { SidebarHamburgerToggle } from "@/components/core/sidebar/sidebar-menu-hamburger-toggle"; +import { PreferencesMobileHeader } from "@/components/profile/preferences/preferences-mobile-header"; import { useApplication } from "@/hooks/store"; import { ProfileSettingsLayout } from "@/layouts/settings-layout"; import { ProfilePreferenceSettingsSidebar } from "./sidebar"; @@ -16,65 +13,26 @@ interface IProfilePreferenceSettingsLayout { export const ProfilePreferenceSettingsLayout: FC = (props) => { const { children, header } = props; - const router = useRouter(); const { theme: themeStore } = useApplication(); - const showMenuItem = () => { - const item = router.asPath.split("/"); - let splittedItem = item[item.length - 1]; - splittedItem = splittedItem.replace(splittedItem[0], splittedItem[0].toUpperCase()); - return splittedItem; - }; - - const profilePreferenceLinks: Array<{ - label: string; - href: string; - }> = [ - { - label: "Theme", - href: `/profile/preferences/theme`, - }, - { - label: "Email", - href: `/profile/preferences/email`, - }, - ]; return ( themeStore.toggleSidebar()} /> - - {showMenuItem()} - - - } - customButtonClassName="flex flex-grow justify-start text-custom-text-200 text-sm" - > - <> - {profilePreferenceLinks.map((link) => ( - - - {link.label} - - - ))} - } > -
- -
- {header} -
{children}
-
+
+ +
+ +
+ {header} +
{children}
+
+
); diff --git a/web/layouts/user-profile-layout/layout.tsx b/web/layouts/user-profile-layout/layout.tsx index ba7a3a88e11..4f173353aa8 100644 --- a/web/layouts/user-profile-layout/layout.tsx +++ b/web/layouts/user-profile-layout/layout.tsx @@ -2,10 +2,10 @@ import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; // components import { ProfileNavbar, ProfileSidebar } from "@/components/profile"; -// hooks -import { useUser } from "@/hooks/store"; // constants import { EUserWorkspaceRoles } from "@/constants/workspace"; +// hooks +import { useUser } from "@/hooks/store"; type Props = { children: React.ReactNode; @@ -28,8 +28,7 @@ export const ProfileAuthWrapper: React.FC = observer((props) => { const isAuthorizedPath = router.pathname.includes("assigned" || "created" || "subscribed"); return ( -
- +
{isAuthorized || !isAuthorizedPath ? ( @@ -40,6 +39,7 @@ export const ProfileAuthWrapper: React.FC = observer((props) => {
)}
+
); }); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx index bc770cc95dd..2d73195fe42 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx @@ -1,11 +1,12 @@ import React, { ReactElement } from "react"; -// layouts +// components import { PageHead } from "@/components/core"; import { UserProfileHeader } from "@/components/headers"; import { ProfileIssuesPage } from "@/components/profile/profile-issues"; +import ProfileIssuesMobileHeader from "@/components/profile/profile-issues-mobile-header"; +// layouts import { AppLayout } from "@/layouts/app-layout"; import { ProfileAuthWrapper } from "@/layouts/user-profile-layout"; -// components // types import { NextPageWithLayout } from "@/lib/types"; @@ -18,7 +19,7 @@ const ProfileAssignedIssuesPage: NextPageWithLayout = () => ( ProfileAssignedIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + } mobileHeader={}> {page} ); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/created.tsx b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx index ef7179f0b96..169ab4841e6 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/created.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx @@ -1,13 +1,14 @@ import { ReactElement } from "react"; // store import { observer } from "mobx-react-lite"; -// layouts +// components import { PageHead } from "@/components/core"; import { UserProfileHeader } from "@/components/headers"; import { ProfileIssuesPage } from "@/components/profile/profile-issues"; +import ProfileIssuesMobileHeader from "@/components/profile/profile-issues-mobile-header"; +// layouts import { AppLayout } from "@/layouts/app-layout"; import { ProfileAuthWrapper } from "@/layouts/user-profile-layout"; -// components // types import { NextPageWithLayout } from "@/lib/types"; @@ -20,7 +21,7 @@ const ProfileCreatedIssuesPage: NextPageWithLayout = () => ( ProfileCreatedIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + } mobileHeader={}> {page} ); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx index e4a871ec8b3..feb7a01602b 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx @@ -1,13 +1,14 @@ import { ReactElement } from "react"; // store import { observer } from "mobx-react-lite"; -// layouts +// components import { PageHead } from "@/components/core"; import { UserProfileHeader } from "@/components/headers"; import { ProfileIssuesPage } from "@/components/profile/profile-issues"; +import ProfileIssuesMobileHeader from "@/components/profile/profile-issues-mobile-header"; +// layouts import { AppLayout } from "@/layouts/app-layout"; import { ProfileAuthWrapper } from "@/layouts/user-profile-layout"; -// components // types import { NextPageWithLayout } from "@/lib/types"; @@ -20,7 +21,7 @@ const ProfileSubscribedIssuesPage: NextPageWithLayout = () => ( ProfileSubscribedIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + } mobileHeader={}> {page} ); diff --git a/web/pages/profile/change-password.tsx b/web/pages/profile/change-password.tsx index 01bedb83d81..6e496862d82 100644 --- a/web/pages/profile/change-password.tsx +++ b/web/pages/profile/change-password.tsx @@ -91,7 +91,7 @@ const ChangePasswordPage: NextPageWithLayout = observer(() => {

Change password

diff --git a/web/pages/profile/index.tsx b/web/pages/profile/index.tsx index 6d2fe4d5489..55c158e8f7a 100644 --- a/web/pages/profile/index.tsx +++ b/web/pages/profile/index.tsx @@ -172,7 +172,7 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => { )} /> setDeactivateAccountModal(false)} /> -
+
@@ -222,7 +222,7 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => {
-
+
{`${watch("first_name")} ${watch("last_name")}`} @@ -238,7 +238,7 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => { */}
-
+

First name* @@ -423,7 +423,7 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => {

- + {({ open }) => ( <> { return ( <> -
+
diff --git a/web/pages/profile/preferences/theme.tsx b/web/pages/profile/preferences/theme.tsx index 09dc9043ee2..0965716b4da 100644 --- a/web/pages/profile/preferences/theme.tsx +++ b/web/pages/profile/preferences/theme.tsx @@ -54,7 +54,7 @@ const ProfilePreferencesThemePage: NextPageWithLayout = observer(() => { <> {currentUser ? ( -
+

Preferences