diff --git a/.vscode/settings.json b/.vscode/settings.json index 7c6853e26..711854ee5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,7 +13,7 @@ "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" }, "vsicons.presets.angular": true, "deepscan.enable": true, diff --git a/apps/web/app/[locale]/[...rest]/page.tsx b/apps/web/app/[locale]/[...rest]/page.tsx new file mode 100644 index 000000000..302287916 --- /dev/null +++ b/apps/web/app/[locale]/[...rest]/page.tsx @@ -0,0 +1,5 @@ +import { notFound } from 'next/navigation'; + +export default function CatchAllPage() { + notFound(); +} diff --git a/apps/web/pages/auth/passcode.tsx b/apps/web/app/[locale]/auth/passcode/page.tsx similarity index 95% rename from apps/web/pages/auth/passcode.tsx rename to apps/web/app/[locale]/auth/passcode/page.tsx index f4067b730..2a6559def 100644 --- a/apps/web/pages/auth/passcode.tsx +++ b/apps/web/app/[locale]/auth/passcode/page.tsx @@ -1,19 +1,30 @@ -import { getAccessTokenCookie } from '@app/helpers'; +'use client'; + +import { getAccessTokenCookie, getActiveUserIdCookie } from '@app/helpers'; import { TAuthenticationPasscode, useAuthenticationPasscode } from '@app/hooks'; import { IClassName } from '@app/interfaces'; import { clsxm } from '@app/utils'; import { AuthCodeInputField, Avatar, BackButton, Button, Card, InputField, SpinnerLoader, Text } from 'lib/components'; import { CircleIcon, TickCircleIconV2 } from 'lib/components/svgs'; import { AuthLayout } from 'lib/layout'; +import { useTranslations } from 'next-intl'; import Link from 'next/link'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/navigation'; import { FormEvent, useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; + import stc from 'string-to-color'; export default function AuthPasscode() { const form = useAuthenticationPasscode(); - const { t } = useTranslation(); + const t = useTranslations(); + const router = useRouter(); + + useEffect(() => { + const userId = getActiveUserIdCookie(); + if (userId) { + router.replace('/'); + } + }, [router]); return ( ) => { @@ -105,7 +116,7 @@ function EmailScreen({ form, className }: { form: TAuthenticationPasscode } & IC } function PasscodeScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { - const { t } = useTranslation(); + const t = useTranslations(); return (
@@ -194,7 +205,7 @@ function PasscodeScreen({ form, className }: { form: TAuthenticationPasscode } & } function WorkSpaceScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { - const { t } = useTranslation(); + const t = useTranslations(); const [selectedWorkspace, setSelectedWorkspace] = useState(0); const [selectedTeam, setSelectedTeam] = useState(''); @@ -227,7 +238,7 @@ function WorkSpaceScreen({ form, className }: { form: TAuthenticationPasscode } if (form.authScreen.screen === 'workspace') { const accessToken = getAccessTokenCookie(); if (accessToken && accessToken.length > 100) { - router.reload(); + router.refresh(); } } }, [form.authScreen, router]); diff --git a/apps/web/pages/auth/team.tsx b/apps/web/app/[locale]/auth/team/page.tsx similarity index 96% rename from apps/web/pages/auth/team.tsx rename to apps/web/app/[locale]/auth/team/page.tsx index 4c4406ac9..8b5692f3f 100644 --- a/apps/web/pages/auth/team.tsx +++ b/apps/web/app/[locale]/auth/team/page.tsx @@ -1,3 +1,5 @@ +'use client'; + import { RECAPTCHA_SITE_KEY } from '@app/constants'; import { useAuthenticationTeam, IStepProps } from '@app/hooks'; import { IClassName } from '@app/interfaces'; @@ -5,7 +7,7 @@ import { clsxm } from '@app/utils'; import { BackButton, BackdropLoader, Button, Card, InputField, SiteReCAPTCHA, Text } from 'lib/components'; import { AuthLayout } from 'lib/layout'; import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; export default function AuthTeam() { const { @@ -20,7 +22,7 @@ export default function AuthTeam() { loading } = useAuthenticationTeam(); - const { t } = useTranslation(); + const t = useTranslations(); return ( @@ -70,7 +72,7 @@ function FillTeamNameForm({ handleOnChange, className }: IStepProps & { errors: Record } & IClassName) { - const { t } = useTranslation(); + const t = useTranslations(); return ( @@ -121,7 +123,7 @@ function FillUserDataForm({ onPreviousStep?: () => void; loading?: boolean; } & IClassName) { - const { t } = useTranslation(); + const t = useTranslations(); return ( @@ -168,7 +170,7 @@ function FillUserDataForm({ } function ReCAPTCHA({ handleOnChange, errors }: { handleOnChange: any; errors: any }) { - const { t } = useTranslation(); + const t = useTranslations(); const [feedback, setFeedback] = useState(''); const content = RECAPTCHA_SITE_KEY.value && ( diff --git a/apps/web/pages/board/index.tsx b/apps/web/app/[locale]/board/page.tsx similarity index 97% rename from apps/web/pages/board/index.tsx rename to apps/web/app/[locale]/board/page.tsx index 6521bf814..7832f5354 100644 --- a/apps/web/pages/board/index.tsx +++ b/apps/web/app/[locale]/board/page.tsx @@ -1,3 +1,5 @@ +'use client'; + import { withAuthentication } from 'lib/app/authenticator'; import { BackdropLoader, Meta } from 'lib/components'; import dynamic from 'next/dynamic'; diff --git a/apps/web/app/[locale]/error.tsx b/apps/web/app/[locale]/error.tsx new file mode 100644 index 000000000..782e52190 --- /dev/null +++ b/apps/web/app/[locale]/error.tsx @@ -0,0 +1,7 @@ +'use client'; + +const Error = () => { + return <>Error Page...; +}; + +export default Error; diff --git a/apps/web/pages/integration/github.tsx b/apps/web/app/[locale]/integration/github/page.tsx similarity index 81% rename from apps/web/pages/integration/github.tsx rename to apps/web/app/[locale]/integration/github/page.tsx index b05ee96d4..6fa2a0290 100644 --- a/apps/web/pages/integration/github.tsx +++ b/apps/web/app/[locale]/integration/github/page.tsx @@ -1,14 +1,20 @@ +'use client'; + import { useIntegrationTenant, useIntegrationTypes } from '@app/hooks'; import { useGitHubIntegration } from '@app/hooks/integrations/useGitHubIntegration'; import { withAuthentication } from 'lib/app/authenticator'; import { BackdropLoader } from 'lib/components'; -import { useTranslation } from 'react-i18next'; -import { useRouter } from 'next/router'; +import { useTranslations } from 'next-intl'; +import { useRouter, useSearchParams } from 'next/navigation'; import { useCallback, useEffect, useRef } from 'react'; const GitHub = () => { const router = useRouter(); - const { t } = useTranslation(); + const searchParams = useSearchParams(); + const installation_id = searchParams?.get('installation_id'); + const setup_action = searchParams?.get('setup_action'); + + const t = useTranslations(); const installing = useRef(false); @@ -28,14 +34,14 @@ const GitHub = () => { const handleInstallGitHub = useCallback(() => { installing.current = true; - if (router && router.query.installation_id && router.query.setup_action) { + if (installation_id && setup_action) { setTimeout(() => { - installGitHub(router.query.installation_id as string, router.query.setup_action as string).then(() => { + installGitHub(installation_id as string, setup_action as string).then(() => { router.replace('/settings/team#integrations'); }); }, 100); } - }, [installGitHub, router]); + }, [installGitHub, router, installation_id, setup_action]); useEffect(() => { if (installing.current) { diff --git a/apps/web/app/[locale]/kanban/page.tsx b/apps/web/app/[locale]/kanban/page.tsx new file mode 100644 index 000000000..198a3e88d --- /dev/null +++ b/apps/web/app/[locale]/kanban/page.tsx @@ -0,0 +1,170 @@ +'use client'; + +import { KanbanTabs } from '@app/constants'; +import { useOrganizationTeams } from '@app/hooks'; +import { useKanban } from '@app/hooks/features/useKanban'; +import KanbanBoardSkeleton from '@components/shared/skeleton/KanbanBoardSkeleton'; +import VerticalLine from '@components/ui/svgs/vertificalline'; +import { withAuthentication } from 'lib/app/authenticator'; +import { Breadcrumb } from 'lib/components'; +import { stackImages } from 'lib/components/kanban-card'; +import { AddIcon } from 'lib/components/svgs'; +import { KanbanView } from 'lib/features/team-members-kanban-view'; +import { MainLayout } from 'lib/layout'; +import Image from 'next/image'; +import { useState } from 'react'; + +const Kanban = () => { + const { data } = useKanban(); + const { activeTeam } = useOrganizationTeams(); + + const [activeTab, setActiveTab] = useState(KanbanTabs.TODAY); + + const imageRadius = 20; + const numberOfImagesDisplayed = 4; + const activeTeamMembers = activeTeam?.members ? activeTeam.members : []; + const totalLength = (activeTeamMembers.length + 1) * imageRadius; + + return ( + <> + +
+ +
+
+

Kanban Board

+
+
+

08:00 ( UTC +04:30 )

+ +
+
+ {activeTeamMembers.map((image: any, index: number) => { + if (index < numberOfImagesDisplayed) { + return ( +
+ {image.title} +
+ ); + } + })} + {activeTeamMembers.length > 4 && ( +
+ {activeTeamMembers.length - numberOfImagesDisplayed}+ +
+ )} +
+
+ + +
+
+
+
+
{ + setActiveTab(KanbanTabs.TODAY); + }} + className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-bold ${ + activeTab === KanbanTabs.TODAY + ? 'border-b-[#3826A6] text-[#3826A6]' + : 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]' + }`} + style={{ + borderBottomWidth: '3px', + borderBottomStyle: 'solid' + }} + > + Today +
+
{ + setActiveTab(KanbanTabs.YESTERDAY); + }} + className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-bold ${ + activeTab === KanbanTabs.YESTERDAY + ? 'border-b-[#3826A6] text-[#3826A6]' + : 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]' + }`} + style={{ + borderBottomWidth: '3px', + borderBottomStyle: 'solid' + }} + > + Yesterday +
+
{ + setActiveTab(KanbanTabs.TOMORROW); + }} + className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-bold ${ + activeTab === KanbanTabs.TOMORROW + ? 'border-b-[#3826A6] text-[#3826A6]' + : 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]' + }`} + style={{ + borderBottomWidth: '3px', + borderBottomStyle: 'solid' + }} + > + Tomorrow +
+
+
+
+
+ {/** TODO:fetch teamtask based on days */} + {/** Kanbanboard for today tasks */} + {activeTab === KanbanTabs.TODAY && ( + <> + {Object.keys(data).length > 0 ? ( + + ) : ( + + )} + + )} + + {/** Kanbanboard for yesterday tasks */} + {activeTab === KanbanTabs.YESTERDAY && ( + <> + {Object.keys(data).length > 0 ? ( + + ) : ( + + )} + + )} + + {/** Kanbanboard for tomorrow tasks */} + {activeTab === KanbanTabs.TOMORROW && ( + <> + {Object.keys(data).length > 0 ? ( + + ) : ( + + )} + + )} +
+ + ); +}; + +export default withAuthentication(Kanban, { displayName: 'Kanban' }); diff --git a/apps/web/app/[locale]/layout.tsx b/apps/web/app/[locale]/layout.tsx new file mode 100644 index 000000000..7c81aa4ec --- /dev/null +++ b/apps/web/app/[locale]/layout.tsx @@ -0,0 +1,71 @@ +/* eslint-disable no-mixed-spaces-and-tabs */ +'use client'; + +import clsx from 'clsx'; +import { Inter } from 'next/font/google'; +import { notFound } from 'next/navigation'; +import { ReactNode } from 'react'; +import { NextIntlClientProvider } from 'next-intl'; +import { RecoilRoot } from 'recoil'; +import { AppState } from 'lib/app/init-state'; + +import 'react-loading-skeleton/dist/skeleton.css'; +import '../../styles/globals.css'; + +const locales = ['en', 'de', 'ar', 'bg', 'zh', 'nl', 'de', 'he', 'it', 'pl', 'pt', 'ru', 'es', 'fr']; + +const inter = Inter({ subsets: ['latin'] }); + +type Props = { + children: ReactNode; + params: { locale: string }; +}; + +// export function generateStaticParams() { +// return locales.map((locale: any) => ({ locale })); +// } + +// export async function generateMetadata({ params: { locale } }: Omit) { +// const t = await getTranslations({ locale, namespace: 'LocaleLayout' }); + +// return { +// title: t('title') +// }; +// } + +export default function LocaleLayout({ children, params: { locale } }: Props) { + // Validate that the incoming `locale` parameter is valid + if (!locales.includes(locale as any)) notFound(); + // Enable static rendering + // unstable_setRequestLocale(locale); + + // eslint-disable-next-line @typescript-eslint/no-var-requires + const messages = require(`../../messages/${locale}.json`); + return ( + + {/* + + + {GA_MEASUREMENT_ID.value && ( + <> + + + )} + */} + + + + + {children} + + + + + ); +} diff --git a/apps/web/pages/meet/index.tsx b/apps/web/app/[locale]/meet/page.tsx similarity index 82% rename from apps/web/pages/meet/index.tsx rename to apps/web/app/[locale]/meet/page.tsx index 83a7585ad..6ae1fd1fc 100644 --- a/apps/web/pages/meet/index.tsx +++ b/apps/web/app/[locale]/meet/page.tsx @@ -1,9 +1,11 @@ +'use client'; + import { useCollaborative, useQuery } from '@app/hooks'; import { getMeetJwtAuthTokenAPI } from '@app/services/client/api'; import { withAuthentication } from 'lib/app/authenticator'; import { BackdropLoader, Meta } from 'lib/components'; import dynamic from 'next/dynamic'; -import { useRouter } from 'next/router'; +import { useRouter, usePathname } from 'next/navigation'; import { useEffect, useMemo, useRef, useState } from 'react'; const Meet = dynamic(() => import('lib/features/integrations/meet'), { @@ -25,26 +27,31 @@ function useMeetJwtToken() { function MeetPage() { const router = useRouter(); + const pathname = usePathname(); const { token } = useMeetJwtToken(); const { randomMeetName } = useCollaborative(); const replaced = useRef(false); const room = useMemo(() => { - const urlParams = router.asPath.substring(router.asPath.indexOf('?')); + if (!pathname) { + return false; + } + + const urlParams = pathname.substring(pathname.indexOf('?')); const searchParams = new URLSearchParams(urlParams); return searchParams.get('room'); - }, [router]); + }, [pathname]); useEffect(() => { - if (!room && router.asPath.startsWith('/meet') && !replaced.current) { + if (!room && pathname?.startsWith('/meet') && !replaced.current) { const url = new URL(window.location.href); url.searchParams.set('room', btoa(randomMeetName())); router.replace(url.pathname + url.search); replaced.current = true; } - }, [room, router, randomMeetName]); + }, [room, router, randomMeetName, pathname]); const roomName = useMemo(() => { return room ? atob(room) : undefined; diff --git a/apps/web/app/[locale]/not-found.tsx b/apps/web/app/[locale]/not-found.tsx new file mode 100644 index 000000000..f20a25c89 --- /dev/null +++ b/apps/web/app/[locale]/not-found.tsx @@ -0,0 +1,17 @@ +'use client'; + +import NotFound from '@components/pages/404'; +import { AuthLayout } from 'lib/layout'; +import { useTranslations } from 'next-intl'; + +const NotFoundPage = () => { + const t = useTranslations(); + + return ( + + + + ); +}; + +export default NotFoundPage; diff --git a/apps/web/app/[locale]/page.tsx b/apps/web/app/[locale]/page.tsx new file mode 100644 index 000000000..b8d750e66 --- /dev/null +++ b/apps/web/app/[locale]/page.tsx @@ -0,0 +1,211 @@ +/* eslint-disable no-mixed-spaces-and-tabs */ + +'use client'; + +import React from 'react'; +import { useOrganizationTeams } from '@app/hooks'; +import { clsxm } from '@app/utils'; +import NoTeam from '@components/pages/main/no-team'; +import { withAuthentication } from 'lib/app/authenticator'; +import { Breadcrumb, Card, Container, Tooltip } from 'lib/components'; +import { PeopleIcon } from 'lib/components/svgs'; +import { + AuthUserTaskInput, + TeamInvitations, + TeamMembers, + Timer, + UnverifiedEmail, + UserTeamCardHeader, + UserTeamBlockHeader +} from 'lib/features'; +import { MainHeader, MainLayout } from 'lib/layout'; +import { useState } from 'react'; +import { IssuesView } from '@app/constants'; +import { TableCellsIcon, QueueListIcon, Squares2X2Icon } from '@heroicons/react/24/solid'; +import { useNetworkState } from '@uidotdev/usehooks'; +import KanbanIcon from '@components/ui/svgs/kanaban'; +import Offline from '@components/pages/offline'; +import UserTeamTableHeader from 'lib/features/team/user-team-table/user-team-table-header'; +import { useTranslations } from 'next-intl'; +import Link from 'next/link'; + +import { setNextPublicEnv } from '@app/env'; +import { JitsuProvider } from '@jitsu/jitsu-react'; +import { Analytics } from '@vercel/analytics/react'; +import type { JitsuOptions } from '@jitsu/jitsu-react/dist/useJitsu'; +import ChatwootWidget from 'lib/features/integrations/chatwoot'; +import type { AppProps } from 'next/app'; +import { JitsuAnalytics } from '../../lib/components/services/jitsu-analytics'; +import 'react-loading-skeleton/dist/skeleton.css'; +import '../../styles/globals.css'; + +type MyAppProps = { + jitsuConf?: JitsuOptions; + jitsuHost?: string; + envs: Record; + user?: any; +}; + +function MainPage({ pageProps }: AppProps) { + const t = useTranslations(); + const { isTeamMember, isTrackingEnabled, activeTeam } = useOrganizationTeams(); + + const breadcrumb = [...JSON.parse(t('pages.home.BREADCRUMB')), activeTeam?.name || '']; + const [view, setView] = useState(IssuesView.CARDS); + const { online } = useNetworkState(); + + if (!online) { + return ; + } + + pageProps?.envs && setNextPublicEnv(pageProps.envs); + + const jitsuConf = pageProps?.jitsuConf; + console.log(`Jitsu Configuration: ${JSON.stringify(jitsuConf)}`); + + const isJitsuEnvsPresent: boolean = jitsuConf?.host !== '' && jitsuConf?.writeKey !== ''; + console.log(`Jitsu Enabled: ${isJitsuEnvsPresent}`); + + return ( + <> + + + + + +
+
+ + +
+ + {/* */} +
+ + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + {isTeamMember ? : null} + {/* Header user card list */} + {view === IssuesView.CARDS && isTeamMember ? ( + + ) : view === IssuesView.BLOCKS ? ( + + ) : view === IssuesView.TABLE ? ( + + ) : null} + + + {/* Divider */} +
+
+ + {isTeamMember ? : } +
+
+ + + ); +} + +function TaskTimerSection({ isTrackingEnabled }: { isTrackingEnabled: boolean }) { + const [showInput, setShowInput] = React.useState(false); + return ( + + {/* Task inputs */} + {/* {showInput && ( */} + + {/* )} */} + + + {/* Timer */} + {isTrackingEnabled ? : null} + + ); +} +export default withAuthentication(MainPage, { displayName: 'MainPage' }); diff --git a/apps/web/pages/permissions/index.tsx b/apps/web/app/[locale]/permissions/page.tsx similarity index 94% rename from apps/web/pages/permissions/index.tsx rename to apps/web/app/[locale]/permissions/page.tsx index 99963cf0d..852af5dc1 100644 --- a/apps/web/pages/permissions/index.tsx +++ b/apps/web/app/[locale]/permissions/page.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useIsMemberManager, useOrganizationTeams, useRolePermissions } from '@app/hooks'; import { useRoles } from '@app/hooks/features/useRoles'; import { IRole } from '@app/interfaces'; @@ -7,11 +9,11 @@ import { withAuthentication } from 'lib/app/authenticator'; import { Breadcrumb, Card, CommonToggle, Container, Divider, Text } from 'lib/components'; import { MainHeader, MainLayout } from 'lib/layout'; import { useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; import { useRecoilState } from 'recoil'; const Permissions = () => { - const { t } = useTranslation(); + const t = useTranslations(); const { activeTeamManagers } = useOrganizationTeams(); const { rolePermissionsFormated, getRolePermissions, updateRolePermission } = useRolePermissions(); @@ -66,7 +68,7 @@ const Permissions = () => { ? 'bg-primary dark:bg-primary-light text-white' : '' }`} - key={role.id} + key={role?.id} onClick={() => { setSelectedRole(role); }} @@ -93,7 +95,6 @@ const Permissions = () => { onChange={() => { handleToggleRolePermission('TIME_TRACKER'); }} - disabled={selectedRole ? false : true} /> @@ -114,7 +115,6 @@ const Permissions = () => { handleToggleRolePermission('ORG_TASK_ADD'); handleToggleRolePermission('ORG_TASK_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -135,7 +135,6 @@ const Permissions = () => { handleToggleRolePermission('ORG_TASK_ADD'); handleToggleRolePermission('ORG_TASK_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -156,7 +155,6 @@ const Permissions = () => { handleToggleRolePermission('ORG_TASK_ADD'); handleToggleRolePermission('ORG_TASK_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -177,7 +175,6 @@ const Permissions = () => { handleToggleRolePermission('ORG_TASK_ADD'); handleToggleRolePermission('ORG_TASK_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -193,7 +190,6 @@ const Permissions = () => { onChange={() => { handleToggleRolePermission('ORG_INVITE_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -214,7 +210,6 @@ const Permissions = () => { handleToggleRolePermission('ORG_EMPLOYEES_EDIT'); handleToggleRolePermission('CHANGE_SELECTED_EMPLOYEE'); }} - disabled={selectedRole ? false : true} /> @@ -233,7 +228,6 @@ const Permissions = () => { onChange={() => { handleToggleRolePermission('ORG_TEAM_JOIN_REQUEST_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -249,7 +243,6 @@ const Permissions = () => { onChange={() => { handleToggleRolePermission('ORG_EMPLOYEES_EDIT'); }} - disabled={selectedRole ? false : true} /> @@ -265,7 +258,6 @@ const Permissions = () => { onChange={() => { handleToggleRolePermission('ORG_TASK_VIEW'); }} - disabled={selectedRole ? false : true} /> diff --git a/apps/web/pages/profile/[memberId].tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx similarity index 95% rename from apps/web/pages/profile/[memberId].tsx rename to apps/web/app/[locale]/profile/[memberId]/page.tsx index 1a27ff937..8415ba76b 100644 --- a/apps/web/pages/profile/[memberId].tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -1,3 +1,5 @@ +'use client'; + /* eslint-disable no-mixed-spaces-and-tabs */ import { imgTitle } from '@app/helpers'; import { useOrganizationTeams, useTimer, useUserProfilePage } from '@app/hooks'; @@ -11,7 +13,7 @@ import { TaskFilter, Timer, TimerStatus, UserProfileTask, getTimerStatusValue, u import { MainHeader, MainLayout } from 'lib/layout'; import Link from 'next/link'; import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; import stc from 'string-to-color'; const Profile = () => { @@ -20,11 +22,8 @@ const Profile = () => { const hook = useTaskFilter(profile); - const { t } = useTranslation(); - const breadcrumb = [ - { title: activeTeam?.name || '', href: '/' }, - ...(t('pages.profile.BREADCRUMB', { returnObjects: true }) as any) - ]; + const t = useTranslations(); + const breadcrumb = [{ title: activeTeam?.name || '', href: '/' }, ...JSON.parse(t('pages.profile.BREADCRUMB'))]; const profileIsAuthUser = useMemo(() => profile.isAuthUser, [profile.isAuthUser]); const hookFilterType = useMemo(() => hook.filterType, [hook.filterType]); diff --git a/apps/web/pages/settings/personal.tsx b/apps/web/app/[locale]/settings/personal/page.tsx similarity index 90% rename from apps/web/pages/settings/personal.tsx rename to apps/web/app/[locale]/settings/personal/page.tsx index 668406a2a..49f506a81 100644 --- a/apps/web/pages/settings/personal.tsx +++ b/apps/web/app/[locale]/settings/personal/page.tsx @@ -1,25 +1,24 @@ +'use client'; + import { withAuthentication } from 'lib/app/authenticator'; import { Breadcrumb, Container } from 'lib/components'; import { MainLayout } from 'lib/layout'; -import { - DangerZone, - // TaskLabelsForm - LeftSideSettingMenu, - PersonalSettingForm, - ProfileAvatar -} from 'lib/settings'; +import { DangerZone, LeftSideSettingMenu, PersonalSettingForm, ProfileAvatar } from 'lib/settings'; import { userState } from '@app/stores'; import SettingsPersonalSkeleton from '@components/shared/skeleton/SettingsPersonalSkeleton'; import { Accordian } from 'lib/components/accordian'; import { ArrowLeft } from 'lib/components/svgs'; import Link from 'next/link'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; import { useRecoilState } from 'recoil'; + const Personal = () => { - const { t } = useTranslation(); + const t = useTranslations(); const [user] = useRecoilState(userState); - const breadcrumb = [...(t('pages.settings.BREADCRUMB', { returnObjects: true }) as any)]; + const breadcrumb = [...JSON.parse(t('pages.settings.BREADCRUMB'))]; + console.log(JSON.parse(t('pages.settings.BREADCRUMB'))); + return ( <> diff --git a/apps/web/pages/settings/team.tsx b/apps/web/app/[locale]/settings/team/page.tsx similarity index 87% rename from apps/web/pages/settings/team.tsx rename to apps/web/app/[locale]/settings/team/page.tsx index 72c6c1acb..0272ddaed 100644 --- a/apps/web/pages/settings/team.tsx +++ b/apps/web/app/[locale]/settings/team/page.tsx @@ -1,3 +1,5 @@ +'use client'; + import { withAuthentication } from 'lib/app/authenticator'; import { Breadcrumb, Card, Container } from 'lib/components'; import { MainLayout } from 'lib/layout'; @@ -10,9 +12,8 @@ import { userState } from '@app/stores'; import NoTeam from '@components/pages/main/no-team'; import { ArrowLeft } from 'lib/components/svgs'; import Link from 'next/link'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; import { useRecoilState } from 'recoil'; -// import { NotificationSettings } from 'lib/settings/notification-setting'; import { Accordian } from 'lib/components/accordian'; import { IntegrationSetting } from 'lib/settings/integration-setting'; import { InvitationSetting } from 'lib/settings/invitation-setting'; @@ -20,11 +21,11 @@ import { IssuesSettings } from 'lib/settings/issues-settings'; import { MemberSetting } from 'lib/settings/member-setting'; const Team = () => { - const { t } = useTranslation(); + const t = useTranslations(); const [user] = useRecoilState(userState); const { isTeamMember, activeTeam } = useOrganizationTeams(); const { isTeamManager } = useIsMemberManager(user); - const breadcrumb = [...(t('pages.settings.BREADCRUMB', { returnObjects: true }) as any)]; + const breadcrumb = [...JSON.parse(t('pages.settings.BREADCRUMB'))]; return ( <> {!user ? ( @@ -56,7 +57,7 @@ const Team = () => { {/* General Settings */}
@@ -69,7 +70,7 @@ const Team = () => { {isTeamManager ? ( @@ -82,7 +83,7 @@ const Team = () => { {isTeamManager ? ( @@ -94,7 +95,7 @@ const Team = () => { {isTeamManager && ( @@ -104,7 +105,7 @@ const Team = () => { {/* Issues Settings */} @@ -122,7 +123,7 @@ const Team = () => { {/* Danger Zone */} diff --git a/apps/web/pages/task/[id].tsx b/apps/web/app/[locale]/task/[id]/page.tsx similarity index 88% rename from apps/web/pages/task/[id].tsx rename to apps/web/app/[locale]/task/[id]/page.tsx index a11b603c8..e8cf5c304 100644 --- a/apps/web/pages/task/[id].tsx +++ b/apps/web/app/[locale]/task/[id]/page.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useOrganizationTeams, useTeamTasks, useUserProfilePage } from '@app/hooks'; import { ChildIssueCard } from '@components/pages/task/ChildIssueCard'; import { RelatedIssueCard } from '@components/pages/task/IssueCard'; @@ -9,34 +11,34 @@ import { withAuthentication } from 'lib/app/authenticator'; import { Breadcrumb, Container } from 'lib/components'; import { ArrowLeft } from 'lib/components/svgs'; import { MainLayout } from 'lib/layout'; -import { useRouter } from 'next/router'; +import { useRouter, useParams } from 'next/navigation'; import { useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; const TaskDetails = () => { const profile = useUserProfilePage(); - const { t } = useTranslation(); + const t = useTranslations(); const router = useRouter(); + const params = useParams(); const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); const { getTaskById, detailedTask: task, getTasksByIdLoading } = useTeamTasks(); - const breadcrumb = [ - { title: activeTeam?.name || '', href: '/' }, - ...t('pages.taskDetails.BREADCRUMB', { returnObjects: true }) - ]; + const id = params?.id; + + const breadcrumb = [{ title: activeTeam?.name || '', href: '/' }, ...JSON.parse(t('pages.taskDetails.BREADCRUMB'))]; useEffect(() => { if ( - router.isReady && + router && // If id is passed in query param - router.query?.id && + id && // Either no task or task id doesn't match query id - (!task || (task && task.id !== router.query?.id)) && + (!task || (task && task.id !== id)) && !getTasksByIdLoading ) { - getTaskById(router.query?.id as string); + getTaskById(id as string); } - }, [getTaskById, router, task, getTasksByIdLoading]); + }, [getTaskById, router, task, getTasksByIdLoading, id]); return ( { const router = useRouter(); - const query = router.query; + const params = useParams(); + const { loadPublicTeamData, loadPublicTeamMiscData, publicTeam: publicTeamData } = usePublicOrganizationTeams(); - const { t } = useTranslation(); + const t = useTranslations(); const [publicTeam, setPublic] = useRecoilState(publicState); useEffect(() => { @@ -26,20 +29,20 @@ const Team = () => { }, [publicTeamData, router]); const loadData = useCallback(() => { - if (query && query.teamId && query.profileLink) { - loadPublicTeamData(query.profileLink as string, query.teamId as string).then((res) => { + if (params?.teamId && params?.profileLink) { + loadPublicTeamData(params?.profileLink as string, params?.teamId as string).then((res) => { if (res?.data?.data?.status === 404) { - router.replace('/404'); + notFound(); } }); setPublic(true); } - }, [loadPublicTeamData, query, router, setPublic]); + }, [loadPublicTeamData, setPublic, params?.teamId, params?.profileLink]); const loadMicsData = useCallback(() => { - if (query && query.teamId && query.profileLink) { - loadPublicTeamMiscData(query.profileLink as string, query.teamId as string); + if (params?.teamId && params?.profileLink) { + loadPublicTeamMiscData(params?.profileLink as string, params?.teamId as string); } - }, [loadPublicTeamMiscData, query]); + }, [loadPublicTeamMiscData, params?.teamId, params?.profileLink]); useEffect(() => { loadData(); @@ -51,7 +54,7 @@ const Team = () => { useRefreshInterval(loadData, 10 * 1000, true); useRefreshInterval(loadMicsData, 30 * 1000, true); - const breadcrumb = [...t('pages.home.BREADCRUMB', { returnObjects: true })]; + const breadcrumb = [...JSON.parse(t('pages.home.BREADCRUMB'))]; return ( diff --git a/apps/web/pages/team/join.tsx b/apps/web/app/[locale]/team/join/page.tsx similarity index 94% rename from apps/web/pages/team/join.tsx rename to apps/web/app/[locale]/team/join/page.tsx index 76357b2fc..7b97e89ff 100644 --- a/apps/web/pages/team/join.tsx +++ b/apps/web/app/[locale]/team/join/page.tsx @@ -1,9 +1,11 @@ +'use client'; + import { AuthCodeInputField, Button, Card, Text } from 'lib/components'; import { AuthLayout } from 'lib/layout'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; export default function AuthPasscode() { - const { t } = useTranslation(); + const t = useTranslations(); return ( diff --git a/apps/web/pages/verify-email/index.tsx b/apps/web/app/[locale]/verify-email/page.tsx similarity index 80% rename from apps/web/pages/verify-email/index.tsx rename to apps/web/app/[locale]/verify-email/page.tsx index 597df5d4d..b3f510b8b 100644 --- a/apps/web/pages/verify-email/index.tsx +++ b/apps/web/app/[locale]/verify-email/page.tsx @@ -1,11 +1,13 @@ +'use client'; + import { useEmailVerifyToken } from '@app/hooks'; import { BackdropLoader } from 'lib/components'; import { MainLayout } from 'lib/layout'; -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; export default function VerifyEmail() { const { loading } = useEmailVerifyToken(); - const { t } = useTranslation(); + const t = useTranslations(); return ( diff --git a/apps/web/app/hooks/auth/useAuthenticationPasscode.ts b/apps/web/app/hooks/auth/useAuthenticationPasscode.ts index 788f9817a..633206587 100644 --- a/apps/web/app/hooks/auth/useAuthenticationPasscode.ts +++ b/apps/web/app/hooks/auth/useAuthenticationPasscode.ts @@ -1,3 +1,5 @@ +'use client'; + import { authFormValidate } from '@app/helpers/validations'; import { ISigninEmailConfirmWorkspaces } from '@app/interfaces'; import { @@ -8,10 +10,10 @@ import { signInWorkspaceAPI } from '@app/services/client/api'; import { AxiosError } from 'axios'; -import { useRouter } from 'next/router'; -import { useCallback, useEffect, useRef, useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { usePathname, useSearchParams } from 'next/navigation'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useQuery } from '../useQuery'; +import { useTranslations } from 'next-intl'; type AuthCodeRef = { focus: () => void; @@ -19,9 +21,20 @@ type AuthCodeRef = { }; export function useAuthenticationPasscode() { - const { query, pathname } = useRouter(); + const pathname = usePathname(); + const query = useSearchParams(); + + const queryTeamId = useMemo(() => { + return query?.get('teamId'); + }, [query]); + const queryEmail = useMemo(() => { + return query?.get('email'); + }, [query]); + const queryCode = useMemo(() => { + return query?.get('code'); + }, [query]); - const { t } = useTranslation(); + const t = useTranslations(); const loginFromQuery = useRef(false); const inputCodeRef = useRef(null); @@ -63,15 +76,15 @@ export function useAuthenticationPasscode() { // If user tries to login from public Team Page as an Already a Member // Redirect to the current team automatically if (pathname === '/team/[teamId]/[profileLink]' && res.data.workspaces.length) { - if (query.teamId) { + if (queryTeamId) { const currentWorkspace = res.data.workspaces.find((workspace) => - workspace.current_teams.map((item) => item.team_id).includes(query.teamId as string) + workspace.current_teams.map((item) => item.team_id).includes(queryTeamId as string) ); signInToWorkspaceRequest({ email: email, token: currentWorkspace?.token as string, - selectedTeam: query.teamId as string + selectedTeam: queryTeamId as string }); } } @@ -192,15 +205,15 @@ export function useAuthenticationPasscode() { * Verifiy immediatly passcode if email and code were passed from url */ useEffect(() => { - if (query.email && query.code && !loginFromQuery.current) { + if (queryEmail && queryCode && !loginFromQuery.current) { setScreen('passcode'); verifyPasscodeRequest({ - email: query.email as string, - code: query.code as string + email: queryEmail as string, + code: queryCode as string }); loginFromQuery.current = true; } - }, [query, verifyPasscodeRequest]); + }, [query, verifyPasscodeRequest, queryEmail, queryCode]); /** * send a fresh auth request handler diff --git a/apps/web/app/hooks/auth/useAuthenticationTeam.ts b/apps/web/app/hooks/auth/useAuthenticationTeam.ts index 785c03145..6fb7d6764 100644 --- a/apps/web/app/hooks/auth/useAuthenticationTeam.ts +++ b/apps/web/app/hooks/auth/useAuthenticationTeam.ts @@ -1,3 +1,6 @@ +/* eslint-disable no-mixed-spaces-and-tabs */ +'use client'; + import { userTimezone } from '@app/helpers/date'; import { authFormValidate } from '@app/helpers/validations'; import { IRegisterDataAPI } from '@app/interfaces'; @@ -15,19 +18,18 @@ export interface IStepProps { form: IRegisterDataAPI; } -const initialValues: IRegisterDataAPI = RECAPTCHA_SITE_KEY ? { - name: '', - email: '', - team: '', - recaptcha: '' -} : -{ - name: '', - email: '', - team: '' -} -; - +const initialValues: IRegisterDataAPI = RECAPTCHA_SITE_KEY + ? { + name: '', + email: '', + team: '', + recaptcha: '' + } + : { + name: '', + email: '', + team: '' + }; export function useAuthenticationTeam() { const [step, setStep] = useState(FIRST_STEP); const [formValues, setFormValues] = useState(initialValues); @@ -48,12 +50,9 @@ export function useAuthenticationTeam() { const withRecaptchaArray = [...noRecaptchaArray, 'recaptcha']; const validationFields = RECAPTCHA_SITE_KEY ? withRecaptchaArray : noRecaptchaArray; - - const { errors, valid } = authFormValidate( - validationFields, - formValues - ); - + + const { errors, valid } = authFormValidate(validationFields, formValues); + if (!valid) { setErrors(errors as any); return; @@ -61,7 +60,7 @@ export function useAuthenticationTeam() { formValues['timezone'] = userTimezone(); infiniteLoading.current = true; - + queryCall(formValues) .then(() => window.location.reload()) .catch((err: AxiosError) => { diff --git a/apps/web/app/hooks/auth/useEmailVerifyToken.ts b/apps/web/app/hooks/auth/useEmailVerifyToken.ts index 032567606..4efd1ae7e 100644 --- a/apps/web/app/hooks/auth/useEmailVerifyToken.ts +++ b/apps/web/app/hooks/auth/useEmailVerifyToken.ts @@ -1,11 +1,16 @@ +'use client'; + import { verifyUserEmailByTokenAPI } from '@app/services/client/api'; import { AxiosError } from 'axios'; -import { useRouter } from 'next/router'; +import { useSearchParams } from 'next/navigation'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useQuery } from '../useQuery'; export function useEmailVerifyToken() { - const { query } = useRouter(); + const searchParams = useSearchParams(); + const email = searchParams?.get('email'); + const token = searchParams?.get('token'); + const loginFromQuery = useRef(false); const [errors, setErrors] = useState({} as { [x: string]: any }); @@ -34,15 +39,15 @@ export function useEmailVerifyToken() { * Verify token immediately if email and token were passed from url */ useEffect(() => { - if (query.email && query.token) { + if (email && token) { verifyEmailRequest({ - email: query.email as string, - token: query.token as string + email: email as string, + token: token as string }); loginFromQuery.current = true; } - }, [query, verifyEmailRequest]); + }, [email, token, verifyEmailRequest]); return { errors, diff --git a/apps/web/app/hooks/features/useAuthenticateUser.ts b/apps/web/app/hooks/features/useAuthenticateUser.ts index 09b5b1fdd..09bf226a3 100644 --- a/apps/web/app/hooks/features/useAuthenticateUser.ts +++ b/apps/web/app/hooks/features/useAuthenticateUser.ts @@ -1,3 +1,5 @@ +'use client'; + import { DEFAULT_APP_PATH } from '@app/constants'; import { removeAuthCookies } from '@app/helpers/cookies'; import { IUser } from '@app/interfaces/IUserData'; diff --git a/apps/web/app/hooks/features/useAutoAssignTask.ts b/apps/web/app/hooks/features/useAutoAssignTask.ts index 4e5b05295..daed8a4bd 100644 --- a/apps/web/app/hooks/features/useAutoAssignTask.ts +++ b/apps/web/app/hooks/features/useAutoAssignTask.ts @@ -1,3 +1,5 @@ +'use client'; + import { useRecoilValue } from 'recoil'; import { timerStatusState, userState } from '@app/stores'; import { useFirstLoad, useSyncRef, useTeamTasks } from '..'; diff --git a/apps/web/app/hooks/features/useImageAssets.ts b/apps/web/app/hooks/features/useImageAssets.ts index 7164968e7..1b7e93d51 100644 --- a/apps/web/app/hooks/features/useImageAssets.ts +++ b/apps/web/app/hooks/features/useImageAssets.ts @@ -1,3 +1,5 @@ +'use client'; + import { getAccessTokenCookie } from '@app/helpers'; import { useCallback, useState } from 'react'; import axios, { AxiosResponse } from 'axios'; diff --git a/apps/web/app/hooks/features/useIssueTypes.ts b/apps/web/app/hooks/features/useIssueTypes.ts index bd67625c1..4a546babf 100644 --- a/apps/web/app/hooks/features/useIssueTypes.ts +++ b/apps/web/app/hooks/features/useIssueTypes.ts @@ -1,3 +1,5 @@ +'use client'; + import { IIssueTypesCreate } from '@app/interfaces'; import { createIssueTypeAPI, getIssueTypeList, deleteIssueTypeAPI, editIssueTypeAPI } from '@app/services/client/api'; import { userState, issueTypesFetchingState, issueTypesListState, activeTeamIdState } from '@app/stores'; diff --git a/apps/web/app/hooks/features/useKanban.ts b/apps/web/app/hooks/features/useKanban.ts index 4217299aa..cf6fed18b 100644 --- a/apps/web/app/hooks/features/useKanban.ts +++ b/apps/web/app/hooks/features/useKanban.ts @@ -62,6 +62,16 @@ export function useKanban() { return columnData[0].isCollapsed } + const reorderStatus = (itemStatus: string, index: number) => { + taskStatusHook.taskStatus.filter((status: ITaskStatusItemList)=> { + return status.name === itemStatus + }).map((status: ITaskStatusItemList)=> { + taskStatusHook.editTaskStatus(status.id, { + order: index + }); + }) + } + return { data: kanbanBoard, isLoading: loading, @@ -69,6 +79,7 @@ export function useKanban() { updateKanbanBoard: setKanbanBoard, updateTaskStatus: updateTask, toggleColumn, - isColumnCollapse + isColumnCollapse, + reorderStatus } } \ No newline at end of file diff --git a/apps/web/app/hooks/features/useLanguageSettings.ts b/apps/web/app/hooks/features/useLanguageSettings.ts index 41534e576..12f041a9a 100644 --- a/apps/web/app/hooks/features/useLanguageSettings.ts +++ b/apps/web/app/hooks/features/useLanguageSettings.ts @@ -1,3 +1,5 @@ +'use client'; + import { APPLICATION_LANGUAGES_CODE } from '@app/constants'; import { getActiveLanguageIdCookie, setActiveLanguageIdCookie } from '@app/helpers/cookies'; import { getLanguageListAPI } from '@app/services/client/api'; diff --git a/apps/web/app/hooks/features/useLinkedTasks.ts b/apps/web/app/hooks/features/useLinkedTasks.ts index 5fb569f6b..bacb3a5e6 100644 --- a/apps/web/app/hooks/features/useLinkedTasks.ts +++ b/apps/web/app/hooks/features/useLinkedTasks.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITeamTask } from '@app/interfaces'; import { useCallback, useEffect, useState } from 'react'; diff --git a/apps/web/app/hooks/features/useOTRefreshInterval.ts b/apps/web/app/hooks/features/useOTRefreshInterval.ts index 91bf1fed7..300b70c30 100644 --- a/apps/web/app/hooks/features/useOTRefreshInterval.ts +++ b/apps/web/app/hooks/features/useOTRefreshInterval.ts @@ -1,3 +1,5 @@ +'use client'; + import { OTRefreshIntervalState } from '@app/stores'; import { useEffect } from 'react'; import { useRecoilState } from 'recoil'; diff --git a/apps/web/app/hooks/features/useOrganizationTeams.ts b/apps/web/app/hooks/features/useOrganizationTeams.ts index a0d6b1fb7..79d11a0da 100644 --- a/apps/web/app/hooks/features/useOrganizationTeams.ts +++ b/apps/web/app/hooks/features/useOrganizationTeams.ts @@ -1,3 +1,5 @@ +'use client'; + import { getActiveTeamIdCookie, setActiveProjectIdCookie, diff --git a/apps/web/app/hooks/features/useRefreshInterval.ts b/apps/web/app/hooks/features/useRefreshInterval.ts index 8eb845df7..8db515d40 100644 --- a/apps/web/app/hooks/features/useRefreshInterval.ts +++ b/apps/web/app/hooks/features/useRefreshInterval.ts @@ -1,3 +1,5 @@ +'use client'; + import { useEffect } from 'react'; import { useCallbackRef } from '../useCallbackRef'; diff --git a/apps/web/app/hooks/features/useTaskEstimation.ts b/apps/web/app/hooks/features/useTaskEstimation.ts index 4f59c4a69..655a3871c 100644 --- a/apps/web/app/hooks/features/useTaskEstimation.ts +++ b/apps/web/app/hooks/features/useTaskEstimation.ts @@ -1,3 +1,5 @@ +'use client'; + import { pad, secondsToTime } from '@app/helpers'; import { ITeamTask, Nullable } from '@app/interfaces'; import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; diff --git a/apps/web/app/hooks/features/useTaskInput.ts b/apps/web/app/hooks/features/useTaskInput.ts index d65ee033a..3d558a4d8 100644 --- a/apps/web/app/hooks/features/useTaskInput.ts +++ b/apps/web/app/hooks/features/useTaskInput.ts @@ -1,3 +1,5 @@ +'use client'; + import { useAuthenticateUser, useModal, useSyncRef } from '@app/hooks'; import { useTeamTasks } from '@app/hooks/features/useTeamTasks'; import { ITaskLabelsItemList, Nullable } from '@app/interfaces'; diff --git a/apps/web/app/hooks/features/useTaskLabels.ts b/apps/web/app/hooks/features/useTaskLabels.ts index 0e0be0685..6a63ef14e 100644 --- a/apps/web/app/hooks/features/useTaskLabels.ts +++ b/apps/web/app/hooks/features/useTaskLabels.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITaskLabelsCreate } from '@app/interfaces'; import { getTaskLabelsList, diff --git a/apps/web/app/hooks/features/useTaskPriorities.ts b/apps/web/app/hooks/features/useTaskPriorities.ts index d6bd22e50..a57f6825b 100644 --- a/apps/web/app/hooks/features/useTaskPriorities.ts +++ b/apps/web/app/hooks/features/useTaskPriorities.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITaskPrioritiesCreate } from '@app/interfaces'; import { getTaskPrioritiesList, diff --git a/apps/web/app/hooks/features/useTaskRelatedIssueType.ts b/apps/web/app/hooks/features/useTaskRelatedIssueType.ts index 1a608d093..6ed96f921 100644 --- a/apps/web/app/hooks/features/useTaskRelatedIssueType.ts +++ b/apps/web/app/hooks/features/useTaskRelatedIssueType.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITaskRelatedIssueTypeCreate } from '@app/interfaces'; import { createTaskRelatedIssueTypeAPI, diff --git a/apps/web/app/hooks/features/useTaskSizes.ts b/apps/web/app/hooks/features/useTaskSizes.ts index 1d19f6fae..1307a0e72 100644 --- a/apps/web/app/hooks/features/useTaskSizes.ts +++ b/apps/web/app/hooks/features/useTaskSizes.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITaskSizesCreate } from '@app/interfaces'; import { createTaskSizesAPI, deleteTaskSizesAPI, getTaskSizesList, editTaskSizesAPI } from '@app/services/client/api'; import { activeTeamIdState, userState } from '@app/stores'; diff --git a/apps/web/app/hooks/features/useTaskStatistics.ts b/apps/web/app/hooks/features/useTaskStatistics.ts index fd44986a7..6c3df1f60 100644 --- a/apps/web/app/hooks/features/useTaskStatistics.ts +++ b/apps/web/app/hooks/features/useTaskStatistics.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITeamTask } from '@app/interfaces'; import { activeTaskTimesheetStatisticsAPI, diff --git a/apps/web/app/hooks/features/useTaskStatus.ts b/apps/web/app/hooks/features/useTaskStatus.ts index 8757bba49..db1738de7 100644 --- a/apps/web/app/hooks/features/useTaskStatus.ts +++ b/apps/web/app/hooks/features/useTaskStatus.ts @@ -1,3 +1,5 @@ +'use client'; + import { ITaskStatusCreate } from '@app/interfaces'; import { createTaskStatusAPI, diff --git a/apps/web/app/hooks/features/useTaskVersion.ts b/apps/web/app/hooks/features/useTaskVersion.ts index 5e5c1958c..a1ebe50f6 100644 --- a/apps/web/app/hooks/features/useTaskVersion.ts +++ b/apps/web/app/hooks/features/useTaskVersion.ts @@ -1,3 +1,5 @@ +'use client'; + /* eslint-disable react-hooks/exhaustive-deps */ import { ITaskVersionCreate } from '@app/interfaces'; import { diff --git a/apps/web/app/hooks/features/useTeamInvitations.ts b/apps/web/app/hooks/features/useTeamInvitations.ts index 6559b6159..bb0134889 100644 --- a/apps/web/app/hooks/features/useTeamInvitations.ts +++ b/apps/web/app/hooks/features/useTeamInvitations.ts @@ -1,3 +1,5 @@ +'use client'; + import { MyInvitationActionEnum } from '@app/interfaces'; import { getTeamInvitationsAPI, diff --git a/apps/web/app/hooks/features/useTeamMember.ts b/apps/web/app/hooks/features/useTeamMember.ts index d06035281..e77796c49 100644 --- a/apps/web/app/hooks/features/useTeamMember.ts +++ b/apps/web/app/hooks/features/useTeamMember.ts @@ -1,3 +1,5 @@ +'use client'; + import { IUser, OT_Member, RoleNameEnum } from '@app/interfaces'; import { activeTeamState } from '@app/stores'; import { useEffect, useState } from 'react'; diff --git a/apps/web/app/hooks/features/useTeamMemberCard.ts b/apps/web/app/hooks/features/useTeamMemberCard.ts index 0538199e0..77510197b 100644 --- a/apps/web/app/hooks/features/useTeamMemberCard.ts +++ b/apps/web/app/hooks/features/useTeamMemberCard.ts @@ -1,3 +1,5 @@ +'use client'; + import { getActiveTaskIdCookie, setActiveTaskIdCookie, setActiveUserTaskCookie } from '@app/helpers'; import { IOrganizationTeamList, ITeamTask, Nullable } from '@app/interfaces'; import { activeTeamTaskState, allTaskStatisticsState } from '@app/stores'; diff --git a/apps/web/app/hooks/features/useTeamTasks.ts b/apps/web/app/hooks/features/useTeamTasks.ts index 140b1f0df..e1116ed44 100644 --- a/apps/web/app/hooks/features/useTeamTasks.ts +++ b/apps/web/app/hooks/features/useTeamTasks.ts @@ -1,3 +1,5 @@ +'use client'; + /* eslint-disable no-mixed-spaces-and-tabs */ import { getActiveTaskIdCookie, diff --git a/apps/web/app/hooks/features/useTimer.ts b/apps/web/app/hooks/features/useTimer.ts index 516be6730..b7a6bfc5a 100644 --- a/apps/web/app/hooks/features/useTimer.ts +++ b/apps/web/app/hooks/features/useTimer.ts @@ -1,3 +1,4 @@ +'use client'; /* eslint-disable no-mixed-spaces-and-tabs */ import { convertMsToTime, secondsToTime } from '@app/helpers/date'; import { ITeamTask } from '@app/interfaces/ITask'; diff --git a/apps/web/app/hooks/features/useTimezoneSettings.ts b/apps/web/app/hooks/features/useTimezoneSettings.ts index f7ca2733c..93841670d 100644 --- a/apps/web/app/hooks/features/useTimezoneSettings.ts +++ b/apps/web/app/hooks/features/useTimezoneSettings.ts @@ -1,3 +1,5 @@ +'use client'; + import { setActiveTimezoneCookie } from '@app/helpers'; import { activeTimezoneState, timezoneListState, activeTimezoneIdState, timezonesFetchingState } from '@app/stores'; import { useCallback, useEffect } from 'react'; diff --git a/apps/web/app/hooks/features/useUserProfilePage.ts b/apps/web/app/hooks/features/useUserProfilePage.ts index 5398c596f..02d28db55 100644 --- a/apps/web/app/hooks/features/useUserProfilePage.ts +++ b/apps/web/app/hooks/features/useUserProfilePage.ts @@ -1,6 +1,8 @@ +'use client'; + import { ITeamTask } from '@app/interfaces'; -import { useRouter } from 'next/router'; -import { useCallback, useEffect } from 'react'; +import { useSearchParams } from 'next/navigation'; +import { useCallback, useEffect, useMemo } from 'react'; import { useAuthenticateUser } from './useAuthenticateUser'; import { useAuthTeamTasks } from './useAuthTeamTasks'; import { useOrganizationTeams } from './useOrganizationTeams'; @@ -14,8 +16,10 @@ export function useUserProfilePage() { const { user: auth } = useAuthenticateUser(); const { getTasksStatsData } = useTaskStatistics(); - const router = useRouter(); - const { memberId } = router.query; + const searchParams = useSearchParams(); + const memberId: string = useMemo(() => { + return (searchParams?.get('memberId') || '') as string; + }, [searchParams]); const members = activeTeam?.members || []; diff --git a/apps/web/app/hooks/useCallbackRef.ts b/apps/web/app/hooks/useCallbackRef.ts index 3f8f59072..12fa75f8f 100644 --- a/apps/web/app/hooks/useCallbackRef.ts +++ b/apps/web/app/hooks/useCallbackRef.ts @@ -1,3 +1,5 @@ +'use client'; + import { useRef } from 'react'; export function useCallbackRef void>(func?: T) { diff --git a/apps/web/app/hooks/useCollaborative.ts b/apps/web/app/hooks/useCollaborative.ts index b285330cf..9e0f7bf0a 100644 --- a/apps/web/app/hooks/useCollaborative.ts +++ b/apps/web/app/hooks/useCollaborative.ts @@ -5,7 +5,7 @@ import { useRecoilState } from 'recoil'; import { useAuthenticateUser } from './features/useAuthenticateUser'; import { useOrganizationTeams } from './features/useOrganizationTeams'; import { BOARD_APP_DOMAIN } from '@app/constants'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/navigation'; import { nanoid } from 'nanoid'; import capitalize from 'lodash/capitalize'; @@ -15,7 +15,7 @@ export function useCollaborative(user?: IUser) { const [collaborativeSelect, setCollaborativeSelect] = useRecoilState(collaborativeSelectState); const [collaborativeMembers, setCollaborativeMembers] = useRecoilState(collaborativeMembersState); - const url = useRouter(); + const router = useRouter(); const randomMeetName = useCallback(() => nanoid(15), []); @@ -59,8 +59,8 @@ export function useCollaborative(user?: IUser) { const onMeetClick = useCallback(() => { const meetName = getMeetRoomName(); - url.push(`/meet?room=${btoa(meetName)}`); - }, [getMeetRoomName, url]); + router.push(`/meet?room=${btoa(meetName)}`); + }, [getMeetRoomName, router]); const onBoardClick = useCallback(() => { const members = collaborativeMembers.map((m) => m.id).join(','); @@ -74,8 +74,8 @@ export function useCollaborative(user?: IUser) { return; } - url.push('/board'); - }, [collaborativeMembers, url]); + router.push('/board'); + }, [collaborativeMembers, router]); return { collaborativeSelect, diff --git a/apps/web/app/hooks/useCustomEmblaCarousel.ts b/apps/web/app/hooks/useCustomEmblaCarousel.ts index 6f123c145..1c3853eed 100644 --- a/apps/web/app/hooks/useCustomEmblaCarousel.ts +++ b/apps/web/app/hooks/useCustomEmblaCarousel.ts @@ -1,3 +1,5 @@ +'use client'; + import useEmblaCarousel, { EmblaOptionsType } from 'embla-carousel-react'; import { useCallback, useEffect, useState } from 'react'; diff --git a/apps/web/app/hooks/useDetectOS.ts b/apps/web/app/hooks/useDetectOS.ts index 977f1fd92..984b65f6c 100644 --- a/apps/web/app/hooks/useDetectOS.ts +++ b/apps/web/app/hooks/useDetectOS.ts @@ -1,3 +1,5 @@ +'use client'; + import { useEffect, useState } from 'react'; const detectOS = (): 'Windows' | 'Mac' | 'Linux' | 'Other' => { diff --git a/apps/web/app/hooks/useFirstLoad.ts b/apps/web/app/hooks/useFirstLoad.ts index d9aca8d21..2432c480b 100644 --- a/apps/web/app/hooks/useFirstLoad.ts +++ b/apps/web/app/hooks/useFirstLoad.ts @@ -1,3 +1,5 @@ +'use client'; + import { useCallback, useState } from 'react'; export function useFirstLoad() { diff --git a/apps/web/app/hooks/useHasMounted.ts b/apps/web/app/hooks/useHasMounted.ts index 4c48725e5..c263b3cba 100644 --- a/apps/web/app/hooks/useHasMounted.ts +++ b/apps/web/app/hooks/useHasMounted.ts @@ -1,3 +1,5 @@ +'use client'; + import { useEffect, useState } from 'react'; export const useHasMounted = () => { diff --git a/apps/web/app/hooks/useHotkeys.ts b/apps/web/app/hooks/useHotkeys.ts index 523324cc1..92eea73e4 100644 --- a/apps/web/app/hooks/useHotkeys.ts +++ b/apps/web/app/hooks/useHotkeys.ts @@ -1,3 +1,5 @@ +'use client'; + import { useEffect } from 'react'; import hotkeys, { HotkeysEvent } from 'hotkeys-js'; diff --git a/apps/web/app/hooks/useLanguage.ts b/apps/web/app/hooks/useLanguage.ts index 3dbc8f8a3..ebbd89d44 100644 --- a/apps/web/app/hooks/useLanguage.ts +++ b/apps/web/app/hooks/useLanguage.ts @@ -1,6 +1,8 @@ +'use client'; + /* eslint-disable react-hooks/exhaustive-deps */ import { currentLanguageState } from '@app/stores'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/navigation'; import { useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useRecoilState } from 'recoil'; @@ -14,16 +16,17 @@ export function useLanguage() { const userSelectedLanguage = window.localStorage.getItem('preferredLanguage') || 'en'; setCurrentLanguage(userSelectedLanguage); }, []); + // TODO Language const changeLanguage = useCallback( (newLanguage: string, forceRedirect = false) => { setCurrentLanguage(newLanguage); - i18n.changeLanguage(newLanguage); + // i18n.changeLanguage(newLanguage); if (typeof window !== 'undefined') { window.localStorage.setItem('preferredLanguage', newLanguage); } if (forceRedirect) { // Navigation to force rerender - router.push({ pathname: router.pathname, query: router.query }, undefined, { locale: newLanguage }); + // router.push({ pathname: router.pathname, query: router.query }, undefined, { locale: newLanguage }); } }, [router, i18n] diff --git a/apps/web/app/hooks/useLeftSettingData.ts b/apps/web/app/hooks/useLeftSettingData.ts index d0d5e2e4b..7967576bf 100644 --- a/apps/web/app/hooks/useLeftSettingData.ts +++ b/apps/web/app/hooks/useLeftSettingData.ts @@ -1,7 +1,7 @@ -import { useTranslation } from 'react-i18next'; +import { useTranslations } from 'next-intl'; export const useLeftSettingData = () => { - const { t } = useTranslation(); + const t = useTranslations(); const PersonalAccordianData = [ { title: t('pages.settingsTeam.GENERAL'), diff --git a/apps/web/app/hooks/useModal.ts b/apps/web/app/hooks/useModal.ts index 8378d2746..57524d1af 100644 --- a/apps/web/app/hooks/useModal.ts +++ b/apps/web/app/hooks/useModal.ts @@ -1,3 +1,5 @@ +'use client'; + import { useCallback, useState } from 'react'; export function useModal() { diff --git a/apps/web/app/hooks/useOutsideClick.ts b/apps/web/app/hooks/useOutsideClick.ts index 6b19fa716..51c02608b 100644 --- a/apps/web/app/hooks/useOutsideClick.ts +++ b/apps/web/app/hooks/useOutsideClick.ts @@ -1,3 +1,5 @@ +'use client'; + import { useCallback, useEffect, useRef } from 'react'; import { useCallbackRef } from './useCallbackRef'; diff --git a/apps/web/app/hooks/useQuery.ts b/apps/web/app/hooks/useQuery.ts index a1517755f..d073fdbfd 100644 --- a/apps/web/app/hooks/useQuery.ts +++ b/apps/web/app/hooks/useQuery.ts @@ -1,3 +1,5 @@ +'use client'; + import { useCallback, useRef, useState } from 'react'; export function useQuery Promise>(queryFunction: T) { diff --git a/apps/web/app/hooks/useSyncRef.ts b/apps/web/app/hooks/useSyncRef.ts index e2caf9936..d3397cab4 100644 --- a/apps/web/app/hooks/useSyncRef.ts +++ b/apps/web/app/hooks/useSyncRef.ts @@ -1,3 +1,5 @@ +'use client'; + import { useMemo, useRef } from 'react'; export function useSyncRef(value: T) { diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 4c886f071..d48047682 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,15 +1,13 @@ +import { ReactNode } from 'react'; + import '../styles/globals.css'; -export default function RootLayout({ - children -}: { - children: React.ReactNode -}) { - return ( - - - {children} - - - ) +type Props = { + children: ReactNode; +}; + +// Since we have a `not-found.tsx` page on the root, a layout file +// is required, even if it's just passing children through. +export default function RootLayout({ children }: Props) { + return children; } diff --git a/apps/web/components/layout/footer/footer.tsx b/apps/web/components/layout/footer/footer.tsx index 9fd546e45..c13533e15 100644 --- a/apps/web/components/layout/footer/footer.tsx +++ b/apps/web/components/layout/footer/footer.tsx @@ -1,7 +1,8 @@ -import { useTranslation } from 'react-i18next'; import ToggleThemeContainer from '../toggleThemeBtns'; +import { useTranslations } from 'next-intl'; + const Footer = () => { - const { t } = useTranslation(); + const t = useTranslations(); return (