diff --git a/apps/web/app/[locale]/[...rest]/page.tsx b/apps/web/app/[locale]/[...rest]/page.tsx index 302287916..404797c6e 100644 --- a/apps/web/app/[locale]/[...rest]/page.tsx +++ b/apps/web/app/[locale]/[...rest]/page.tsx @@ -1,5 +1,10 @@ +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; import { notFound } from 'next/navigation'; export default function CatchAllPage() { notFound(); } + +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE, rest: [] }]; +} diff --git a/apps/web/app/[locale]/auth/passcode/component.tsx b/apps/web/app/[locale]/auth/passcode/component.tsx new file mode 100644 index 000000000..5b286ec54 --- /dev/null +++ b/apps/web/app/[locale]/auth/passcode/component.tsx @@ -0,0 +1,388 @@ +'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/navigation'; +import { FormEvent, useCallback, useEffect, useRef, useState } from 'react'; + +import stc from 'string-to-color'; + +function AuthPasscode() { + const form = useAuthenticationPasscode(); + const t = useTranslations(); + const router = useRouter(); + + useEffect(() => { + const userId = getActiveUserIdCookie(); + if (userId) { + router.replace('/'); + } + }, [router]); + + return ( + + {t('pages.authLogin.HEADING_WORKSPACE_LINE1')} +
+ {t('pages.authLogin.HEADING_WORKSPACE_LINE2')} + + ) : ( + t('pages.authLogin.HEADING_DESCRIPTION') + ) + } + > +
+
+ {form.authScreen.screen === 'email' && } + {form.authScreen.screen === 'passcode' && ( + + )} + + {form.authScreen.screen === 'workspace' && ( + + )} +
+
+
+ ); +} + +function EmailScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { + const t = useTranslations(); + + const handleSendCode = useCallback( + (e: FormEvent) => { + e.preventDefault(); + + form.sendAuthCodeHandler().then(() => { + form.authScreen.setScreen('passcode'); + }); + }, + [form] + ); + + return ( +
+ +
+ + {t('pages.auth.ENTER_EMAIL')} + + + {/* Email input */} + + +
+ {/* Send code */} +
+
+ {t('common.DONT_HAVE_ACCOUNT')} + + {t('common.REGISTER')} + +
+
+ + +
+
+
+
+ ); +} + +function PasscodeScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { + const t = useTranslations(); + const inputsRef = useRef>([]); + const resetForm = () => { + if (inputsRef.current) { + for (let i = 0; i < inputsRef.current.length; i++) { + inputsRef.current[i].value = ''; + } + inputsRef.current[0].focus(); + } + }; + return ( +
+ +
+ + {t('pages.auth.LOGIN')} + + + {/* Auth code input */} +
+
+ + {t('pages.auth.INPUT_INVITE_CODE')} + + resetForm()} + className="text-xs font-normal cursor-pointer hover:underline text-gray-400" + > + {t('common.RESET')} + +
+ + { + form.setFormValues((v) => ({ ...v, code })); + }} + hintType={ + form.errors['code'] || form.errors['email'] + ? 'error' + : form.authenticated + ? 'success' + : undefined + } + autoFocus={form.authScreen.screen === 'passcode'} + /> + {(form.errors['code'] || form.errors['email']) && ( + + {form.errors['code'] || form.errors['email']} + + )} +
+ +
+ {/* Send code */} +
+
+ + {t('pages.auth.UNRECEIVED_CODE')} + + + {!form.sendCodeLoading && ( + + )} + {form.sendCodeLoading && } +
+ +
+ { + form.authScreen.setScreen('email'); + form.setErrors({}); + }} + /> +
+
+ + +
+
+
+
+ ); +} + +function WorkSpaceScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { + const t = useTranslations(); + + const [selectedWorkspace, setSelectedWorkspace] = useState(0); + const [selectedTeam, setSelectedTeam] = useState(''); + const router = useRouter(); + + const signInToWorkspace = useCallback( + (e: any) => { + if (typeof selectedWorkspace !== 'undefined') { + form.handleWorkspaceSubmit(e, form.workspaces[selectedWorkspace].token, selectedTeam); + } + }, + [selectedWorkspace, selectedTeam, form] + ); + + useEffect(() => { + if (form.workspaces.length === 1) { + setSelectedWorkspace(0); + } + + const currentTeams = form.workspaces[0]?.current_teams; + + if (form.workspaces.length === 1 && currentTeams?.length === 1) { + setSelectedTeam(currentTeams[0].team_id); + } + if (form.workspaces.length === 1 && (currentTeams?.length || 0) <= 1) { + setTimeout(() => { + document.getElementById('continue-to-workspace')?.click(); + }, 100); + } + }, [form.workspaces]); + + useEffect(() => { + if (form.authScreen.screen === 'workspace') { + const accessToken = getAccessTokenCookie(); + if (accessToken && accessToken.length > 100) { + router.refresh(); + } + } + }, [form.authScreen, router]); + + console.log(form); + + return ( +
+ +
+ + {t('pages.auth.SELECT_WORKSPACE')} + + +
+ {form.workspaces?.map((worksace, index) => ( +
+
+
+ {worksace.user.tenant.name} + { + setSelectedWorkspace(index); + if ( + selectedTeam && + !worksace.current_teams + ?.map((team) => team.team_id) + .includes(selectedTeam) + ) { + setSelectedTeam(worksace.current_teams[0].team_id); + } + }} + > + {selectedWorkspace === index ? ( + + ) : ( + + )} + +
+ + {/*
*/} +
+ {worksace.current_teams?.map((team) => ( +
+ + +
+ + {team.team_name} + + ({team.team_member_count}) +
+
+ { + setSelectedTeam(team.team_id); + if (selectedWorkspace !== index) { + setSelectedWorkspace(index); + } + }} + > + {selectedTeam === team.team_id ? ( + + ) : ( + + )} + +
+ ))} +
+
+
+ ))} +
+ +
+
+
+ { + form.authScreen.setScreen('email'); + form.setErrors({}); + }} + /> +
+
+ + +
+
+
+
+ ); +} + +export default AuthPasscode; diff --git a/apps/web/app/[locale]/auth/passcode/page.tsx b/apps/web/app/[locale]/auth/passcode/page.tsx index 43b673bc2..79cbc90df 100644 --- a/apps/web/app/[locale]/auth/passcode/page.tsx +++ b/apps/web/app/[locale]/auth/passcode/page.tsx @@ -1,388 +1,10 @@ -'use client'; +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import AuthPasscode from './component'; -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/navigation'; -import { FormEvent, useCallback, useEffect, useRef, useState } from 'react'; - -import stc from 'string-to-color'; - -function AuthPasscode() { - const form = useAuthenticationPasscode(); - const t = useTranslations(); - const router = useRouter(); - - useEffect(() => { - const userId = getActiveUserIdCookie(); - if (userId) { - router.replace('/'); - } - }, [router]); - - return ( - - {t('pages.authLogin.HEADING_WORKSPACE_LINE1')} -
- {t('pages.authLogin.HEADING_WORKSPACE_LINE2')} - - ) : ( - t('pages.authLogin.HEADING_DESCRIPTION') - ) - } - > -
-
- {form.authScreen.screen === 'email' && } - {form.authScreen.screen === 'passcode' && ( - - )} - - {form.authScreen.screen === 'workspace' && ( - - )} -
-
-
- ); +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; } -export default AuthPasscode; - -function EmailScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { - const t = useTranslations(); - - const handleSendCode = useCallback( - (e: FormEvent) => { - e.preventDefault(); - - form.sendAuthCodeHandler().then(() => { - form.authScreen.setScreen('passcode'); - }); - }, - [form] - ); - - return ( -
- -
- - {t('pages.auth.ENTER_EMAIL')} - - - {/* Email input */} - - -
- {/* Send code */} -
-
- {t('common.DONT_HAVE_ACCOUNT')} - - {t('common.REGISTER')} - -
-
- - -
-
-
-
- ); -} - -function PasscodeScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { - const t = useTranslations(); - const inputsRef = useRef>([]); - const resetForm = () => { - if (inputsRef.current) { - for (let i = 0; i < inputsRef.current.length; i++) { - inputsRef.current[i].value = ''; - } - inputsRef.current[0].focus(); - } - }; - return ( -
- -
- - {t('pages.auth.LOGIN')} - - - {/* Auth code input */} -
-
- - {t('pages.auth.INPUT_INVITE_CODE')} - - resetForm()} - className="text-xs font-normal cursor-pointer hover:underline text-gray-400" - > - {t('common.RESET')} - -
- - { - form.setFormValues((v) => ({ ...v, code })); - }} - hintType={ - form.errors['code'] || form.errors['email'] - ? 'error' - : form.authenticated - ? 'success' - : undefined - } - autoFocus={form.authScreen.screen === 'passcode'} - /> - {(form.errors['code'] || form.errors['email']) && ( - - {form.errors['code'] || form.errors['email']} - - )} -
- -
- {/* Send code */} -
-
- - {t('pages.auth.UNRECEIVED_CODE')} - - - {!form.sendCodeLoading && ( - - )} - {form.sendCodeLoading && } -
- -
- { - form.authScreen.setScreen('email'); - form.setErrors({}); - }} - /> -
-
- - -
-
-
-
- ); -} - -function WorkSpaceScreen({ form, className }: { form: TAuthenticationPasscode } & IClassName) { - const t = useTranslations(); - - const [selectedWorkspace, setSelectedWorkspace] = useState(0); - const [selectedTeam, setSelectedTeam] = useState(''); - const router = useRouter(); - - const signInToWorkspace = useCallback( - (e: any) => { - if (typeof selectedWorkspace !== 'undefined') { - form.handleWorkspaceSubmit(e, form.workspaces[selectedWorkspace].token, selectedTeam); - } - }, - [selectedWorkspace, selectedTeam, form] - ); - - useEffect(() => { - if (form.workspaces.length === 1) { - setSelectedWorkspace(0); - } - - const currentTeams = form.workspaces[0]?.current_teams; - - if (form.workspaces.length === 1 && currentTeams?.length === 1) { - setSelectedTeam(currentTeams[0].team_id); - } - if (form.workspaces.length === 1 && (currentTeams?.length || 0) <= 1) { - setTimeout(() => { - document.getElementById('continue-to-workspace')?.click(); - }, 100); - } - }, [form.workspaces]); - - useEffect(() => { - if (form.authScreen.screen === 'workspace') { - const accessToken = getAccessTokenCookie(); - if (accessToken && accessToken.length > 100) { - router.refresh(); - } - } - }, [form.authScreen, router]); - - console.log(form); - - return ( -
- -
- - {t('pages.auth.SELECT_WORKSPACE')} - - -
- {form.workspaces?.map((worksace, index) => ( -
-
-
- {worksace.user.tenant.name} - { - setSelectedWorkspace(index); - if ( - selectedTeam && - !worksace.current_teams - ?.map((team) => team.team_id) - .includes(selectedTeam) - ) { - setSelectedTeam(worksace.current_teams[0].team_id); - } - }} - > - {selectedWorkspace === index ? ( - - ) : ( - - )} - -
- - {/*
*/} -
- {worksace.current_teams?.map((team) => ( -
- - -
- - {team.team_name} - - ({team.team_member_count}) -
-
- { - setSelectedTeam(team.team_id); - if (selectedWorkspace !== index) { - setSelectedWorkspace(index); - } - }} - > - {selectedTeam === team.team_id ? ( - - ) : ( - - )} - -
- ))} -
-
-
- ))} -
- -
-
-
- { - form.authScreen.setScreen('email'); - form.setErrors({}); - }} - /> -
-
- - -
-
-
-
- ); +export default function Page() { + return ; } diff --git a/apps/web/app/[locale]/auth/team/component.tsx b/apps/web/app/[locale]/auth/team/component.tsx new file mode 100644 index 000000000..057a36221 --- /dev/null +++ b/apps/web/app/[locale]/auth/team/component.tsx @@ -0,0 +1,199 @@ +'use client'; + +import { RECAPTCHA_SITE_KEY } from '@app/constants'; +import { useAuthenticationTeam, IStepProps } from '@app/hooks'; +import { IClassName } from '@app/interfaces'; +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 { useTranslations } from 'next-intl'; + +function AuthTeam() { + const { + handleSubmit, + step, + FIRST_STEP, + // SECOND_STEP, + handleOnChange, + setStep, + errors, + formValues, + loading + } = useAuthenticationTeam(); + + const t = useTranslations(); + + return ( + <> + +
+
+
+
+ +
+ +
+ setStep(FIRST_STEP)} + loading={loading} + /> +
+
+
+
+ +
+ + ); +} + +/** + * First step form Component + * + * @param param0 + * @returns + */ +function FillTeamNameForm({ + form, + errors, + handleOnChange, + className +}: IStepProps & { errors: Record } & IClassName) { + const t = useTranslations(); + + return ( + +
+ + {t('pages.authTeam.INPUT_TEAM_NAME')} + + + + +
+ + {t('pages.auth.LOGIN')} + + + +
+
+
+ ); +} + +/** + * Second step form component + * + * @param param0 + * @returns + */ +function FillUserDataForm({ + form, + errors, + handleOnChange, + onPreviousStep, + loading, + className +}: IStepProps & { + errors: Record; + onPreviousStep?: () => void; + loading?: boolean; +} & IClassName) { + const t = useTranslations(); + + return ( + +
+ + {t('pages.authTeam.CREATE_FIRST_TEAM')} + + +
+ + + +
+ +
+ + + +
+
+
+ ); +} + +function ReCAPTCHA({ handleOnChange, errors }: { handleOnChange: any; errors: any }) { + const t = useTranslations(); + const [feedback, setFeedback] = useState(''); + + const content = RECAPTCHA_SITE_KEY.value && ( +
+
+ { + handleOnChange({ target: { name: 'recaptcha', value: res } }); + setFeedback(''); + }} + onErrored={() => setFeedback(t('errors.NETWORK_ISSUE'))} + /> + {(errors['recaptcha'] || feedback) && ( + {errors['recaptcha'] || feedback} + )} +
+
+ ); + + return content || <>; +} + +export default AuthTeam; diff --git a/apps/web/app/[locale]/auth/team/page.tsx b/apps/web/app/[locale]/auth/team/page.tsx index 057a36221..92a1bdd3e 100644 --- a/apps/web/app/[locale]/auth/team/page.tsx +++ b/apps/web/app/[locale]/auth/team/page.tsx @@ -1,199 +1,10 @@ -'use client'; +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import AuthTeam from './component'; -import { RECAPTCHA_SITE_KEY } from '@app/constants'; -import { useAuthenticationTeam, IStepProps } from '@app/hooks'; -import { IClassName } from '@app/interfaces'; -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 { useTranslations } from 'next-intl'; - -function AuthTeam() { - const { - handleSubmit, - step, - FIRST_STEP, - // SECOND_STEP, - handleOnChange, - setStep, - errors, - formValues, - loading - } = useAuthenticationTeam(); - - const t = useTranslations(); - - return ( - <> - -
-
-
-
- -
- -
- setStep(FIRST_STEP)} - loading={loading} - /> -
-
-
-
- -
- - ); +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; } -/** - * First step form Component - * - * @param param0 - * @returns - */ -function FillTeamNameForm({ - form, - errors, - handleOnChange, - className -}: IStepProps & { errors: Record } & IClassName) { - const t = useTranslations(); - - return ( - -
- - {t('pages.authTeam.INPUT_TEAM_NAME')} - - - - -
- - {t('pages.auth.LOGIN')} - - - -
-
-
- ); +export default function Page() { + return ; } - -/** - * Second step form component - * - * @param param0 - * @returns - */ -function FillUserDataForm({ - form, - errors, - handleOnChange, - onPreviousStep, - loading, - className -}: IStepProps & { - errors: Record; - onPreviousStep?: () => void; - loading?: boolean; -} & IClassName) { - const t = useTranslations(); - - return ( - -
- - {t('pages.authTeam.CREATE_FIRST_TEAM')} - - -
- - - -
- -
- - - -
-
-
- ); -} - -function ReCAPTCHA({ handleOnChange, errors }: { handleOnChange: any; errors: any }) { - const t = useTranslations(); - const [feedback, setFeedback] = useState(''); - - const content = RECAPTCHA_SITE_KEY.value && ( -
-
- { - handleOnChange({ target: { name: 'recaptcha', value: res } }); - setFeedback(''); - }} - onErrored={() => setFeedback(t('errors.NETWORK_ISSUE'))} - /> - {(errors['recaptcha'] || feedback) && ( - {errors['recaptcha'] || feedback} - )} -
-
- ); - - return content || <>; -} - -export default AuthTeam; diff --git a/apps/web/app/[locale]/board/component.tsx b/apps/web/app/[locale]/board/component.tsx new file mode 100644 index 000000000..b6fefefae --- /dev/null +++ b/apps/web/app/[locale]/board/component.tsx @@ -0,0 +1,25 @@ +'use client'; + +import { withAuthentication } from 'lib/app/authenticator'; +import { BackdropLoader, Meta } from 'lib/components'; +import dynamic from 'next/dynamic'; + +const Board = dynamic(() => import('lib/features/integrations/boards'), { + ssr: false, + loading: () => +}); + +function BoardPage() { + return ( + <> +
+ + +
+ + ); +} + +export default withAuthentication(BoardPage, { + displayName: 'BoardIntegrationPage' +}); diff --git a/apps/web/app/[locale]/board/page.tsx b/apps/web/app/[locale]/board/page.tsx index b6fefefae..832a406e6 100644 --- a/apps/web/app/[locale]/board/page.tsx +++ b/apps/web/app/[locale]/board/page.tsx @@ -1,25 +1,10 @@ -'use client'; +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import BoardPage from './component'; -import { withAuthentication } from 'lib/app/authenticator'; -import { BackdropLoader, Meta } from 'lib/components'; -import dynamic from 'next/dynamic'; - -const Board = dynamic(() => import('lib/features/integrations/boards'), { - ssr: false, - loading: () => -}); - -function BoardPage() { - return ( - <> -
- - -
- - ); +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; } -export default withAuthentication(BoardPage, { - displayName: 'BoardIntegrationPage' -}); +export default function Page() { + return ; +} diff --git a/apps/web/app/[locale]/integration/github/component.tsx b/apps/web/app/[locale]/integration/github/component.tsx new file mode 100644 index 000000000..666fa38db --- /dev/null +++ b/apps/web/app/[locale]/integration/github/component.tsx @@ -0,0 +1,71 @@ +'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 { useTranslations } from 'next-intl'; +import { useRouter, useSearchParams } from 'next/navigation'; +import { useCallback, useEffect, useRef } from 'react'; + +const GitHub = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const installation_id = searchParams?.get('installation_id'); + const setup_action = searchParams?.get('setup_action'); + + const t = useTranslations(); + + const installing = useRef(false); + + const { installGitHub, getRepositories } = useGitHubIntegration(); + const { getIntegrationTenant, loading: integrationTenantLoading, integrationTenant } = useIntegrationTenant(); + const { loading: loadingIntegrationTypes, integrationTypes, getIntegrationTypes } = useIntegrationTypes(); + + const handleInstallGitHub = useCallback(() => { + installing.current = true; + + if (installation_id && setup_action) { + setTimeout(() => { + installGitHub(installation_id as string, setup_action as string).then(() => { + router.replace('/settings/team#integrations'); + }); + }, 100); + } + }, [installGitHub, router, installation_id, setup_action]); + + useEffect(() => { + if (installing.current) { + return; + } + + handleInstallGitHub(); + }, [handleInstallGitHub]); + + useEffect(() => { + if (!integrationTenantLoading && integrationTenant && integrationTenant.length && integrationTenant[0]?.id) { + getRepositories(integrationTenant[0].id); + } + }, [integrationTenantLoading, integrationTenant, getRepositories]); + + useEffect(() => { + if (!loadingIntegrationTypes && integrationTypes.length === 0) { + getIntegrationTypes().then((types) => { + const allIntegrations = types.find((item: any) => item.name === 'All Integrations'); + if (allIntegrations && allIntegrations?.id) { + getIntegrationTenant('Github'); + } + }); + } + }, [loadingIntegrationTypes, integrationTypes, getIntegrationTypes, getIntegrationTenant]); + + return ( +
+ +
+ ); +}; + +export default withAuthentication(GitHub, { + displayName: 'GitHubIntegrationPage' +}); diff --git a/apps/web/app/[locale]/integration/github/page.tsx b/apps/web/app/[locale]/integration/github/page.tsx index 666fa38db..01902a261 100644 --- a/apps/web/app/[locale]/integration/github/page.tsx +++ b/apps/web/app/[locale]/integration/github/page.tsx @@ -1,71 +1,10 @@ -'use client'; +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import GitHubPage from './component'; -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 { useTranslations } from 'next-intl'; -import { useRouter, useSearchParams } from 'next/navigation'; -import { useCallback, useEffect, useRef } from 'react'; +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; +} -const GitHub = () => { - const router = useRouter(); - const searchParams = useSearchParams(); - const installation_id = searchParams?.get('installation_id'); - const setup_action = searchParams?.get('setup_action'); - - const t = useTranslations(); - - const installing = useRef(false); - - const { installGitHub, getRepositories } = useGitHubIntegration(); - const { getIntegrationTenant, loading: integrationTenantLoading, integrationTenant } = useIntegrationTenant(); - const { loading: loadingIntegrationTypes, integrationTypes, getIntegrationTypes } = useIntegrationTypes(); - - const handleInstallGitHub = useCallback(() => { - installing.current = true; - - if (installation_id && setup_action) { - setTimeout(() => { - installGitHub(installation_id as string, setup_action as string).then(() => { - router.replace('/settings/team#integrations'); - }); - }, 100); - } - }, [installGitHub, router, installation_id, setup_action]); - - useEffect(() => { - if (installing.current) { - return; - } - - handleInstallGitHub(); - }, [handleInstallGitHub]); - - useEffect(() => { - if (!integrationTenantLoading && integrationTenant && integrationTenant.length && integrationTenant[0]?.id) { - getRepositories(integrationTenant[0].id); - } - }, [integrationTenantLoading, integrationTenant, getRepositories]); - - useEffect(() => { - if (!loadingIntegrationTypes && integrationTypes.length === 0) { - getIntegrationTypes().then((types) => { - const allIntegrations = types.find((item: any) => item.name === 'All Integrations'); - if (allIntegrations && allIntegrations?.id) { - getIntegrationTenant('Github'); - } - }); - } - }, [loadingIntegrationTypes, integrationTypes, getIntegrationTypes, getIntegrationTenant]); - - return ( -
- -
- ); -}; - -export default withAuthentication(GitHub, { - displayName: 'GitHubIntegrationPage' -}); +export default function Page() { + return ; +} diff --git a/apps/web/app/[locale]/kanban/page.tsx b/apps/web/app/[locale]/kanban/page.tsx index 4c8ff86c8..c211b8374 100644 --- a/apps/web/app/[locale]/kanban/page.tsx +++ b/apps/web/app/[locale]/kanban/page.tsx @@ -5,8 +5,10 @@ import { useOrganizationTeams } from '@app/hooks'; import { useKanban } from '@app/hooks/features/useKanban'; import KanbanBoardSkeleton from '@components/shared/skeleton/KanbanBoardSkeleton'; import { withAuthentication } from 'lib/app/authenticator'; -import { Breadcrumb, Button, Dropdown, InputField } from 'lib/components'; +import { Breadcrumb, Button, InputField } from 'lib/components'; import { AddIcon, PeopleIcon, SearchNormalIcon, Settings4Icon } from 'lib/components/svgs'; +import { ChevronDownIcon } from '@heroicons/react/20/solid'; + import { KanbanView } from 'lib/features/team-members-kanban-view'; import { MainLayout } from 'lib/layout'; import { useState } from 'react'; @@ -16,6 +18,8 @@ import ImageComponent, { ImageOverlapperProps } from 'lib/components/image-overl import Separator from '@components/ui/separator'; import { clsxm } from '@app/utils'; import HeaderTabs from '@components/pages/main/header-tabs'; +import { Select, SelectContent, SelectItem } from '@components/ui/select'; +import { SelectTrigger } from '@radix-ui/react-select'; const Kanban = () => { const { data } = useKanban(); @@ -46,38 +50,13 @@ const Kanban = () => { { name: t('common.YESTERDAY'), value: KanbanTabs.YESTERDAY }, { name: t('common.TOMORROW'), value: KanbanTabs.TOMORROW } ]; - // eslint-disable-next-line react/no-unstable-nested-components - const Label = ({ active, selected }: { active: string; selected: string }) => ( -
- {active} -
- ); - const sampleDropdownItem = (key: string) => { - const data = { - key: '1', - Label: Label, - selectedLabel: {key}, - itemTitle: key - // other properties can be added as needed - }; - return data; - }; return ( <> -
-
- +
+
+
@@ -125,26 +104,40 @@ const Kanban = () => { ))}
- - + +
-
+ {/*
*/}
{/** TODO:fetch teamtask based on days */} {activeTab && ( // add filter for today, yesterday and tomorrow -
+
{Object.keys(data).length > 0 ? ( ) : ( diff --git a/apps/web/app/[locale]/meet/component.tsx b/apps/web/app/[locale]/meet/component.tsx new file mode 100644 index 000000000..6ae1fd1fc --- /dev/null +++ b/apps/web/app/[locale]/meet/component.tsx @@ -0,0 +1,71 @@ +'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, usePathname } from 'next/navigation'; +import { useEffect, useMemo, useRef, useState } from 'react'; + +const Meet = dynamic(() => import('lib/features/integrations/meet'), { + ssr: false, + loading: () => +}); + +function useMeetJwtToken() { + const [token, setToken] = useState(); + const { queryCall, loading } = useQuery(getMeetJwtAuthTokenAPI); + + useEffect(() => { + queryCall().then((res) => setToken(res.data.token)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return { loading, token }; +} + +function MeetPage() { + const router = useRouter(); + const pathname = usePathname(); + const { token } = useMeetJwtToken(); + const { randomMeetName } = useCollaborative(); + const replaced = useRef(false); + + const room = useMemo(() => { + if (!pathname) { + return false; + } + + const urlParams = pathname.substring(pathname.indexOf('?')); + const searchParams = new URLSearchParams(urlParams); + + return searchParams.get('room'); + }, [pathname]); + + useEffect(() => { + 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, pathname]); + + const roomName = useMemo(() => { + return room ? atob(room) : undefined; + }, [room]); + + return ( + <> + + {token && roomName && } + + ); +} + +export default withAuthentication(MeetPage, { + displayName: 'MeetPage', + showPageSkeleton: false +}); diff --git a/apps/web/app/[locale]/meet/page.tsx b/apps/web/app/[locale]/meet/page.tsx index 6ae1fd1fc..10f29fab0 100644 --- a/apps/web/app/[locale]/meet/page.tsx +++ b/apps/web/app/[locale]/meet/page.tsx @@ -1,71 +1,10 @@ -'use client'; +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import MeetPage from './component'; -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, usePathname } from 'next/navigation'; -import { useEffect, useMemo, useRef, useState } from 'react'; - -const Meet = dynamic(() => import('lib/features/integrations/meet'), { - ssr: false, - loading: () => -}); - -function useMeetJwtToken() { - const [token, setToken] = useState(); - const { queryCall, loading } = useQuery(getMeetJwtAuthTokenAPI); - - useEffect(() => { - queryCall().then((res) => setToken(res.data.token)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return { loading, token }; +export default function Page() { + return ; } -function MeetPage() { - const router = useRouter(); - const pathname = usePathname(); - const { token } = useMeetJwtToken(); - const { randomMeetName } = useCollaborative(); - const replaced = useRef(false); - - const room = useMemo(() => { - if (!pathname) { - return false; - } - - const urlParams = pathname.substring(pathname.indexOf('?')); - const searchParams = new URLSearchParams(urlParams); - - return searchParams.get('room'); - }, [pathname]); - - useEffect(() => { - 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, pathname]); - - const roomName = useMemo(() => { - return room ? atob(room) : undefined; - }, [room]); - - return ( - <> - - {token && roomName && } - - ); +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; } - -export default withAuthentication(MeetPage, { - displayName: 'MeetPage', - showPageSkeleton: false -}); diff --git a/apps/web/app/[locale]/page-component.tsx b/apps/web/app/[locale]/page-component.tsx new file mode 100644 index 000000000..8b9b40e64 --- /dev/null +++ b/apps/web/app/[locale]/page-component.tsx @@ -0,0 +1,142 @@ +/* eslint-disable no-mixed-spaces-and-tabs */ + +'use client'; + +import React, { useEffect } 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 } 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 { IssuesView } from '@app/constants'; +import { useNetworkState } from '@uidotdev/usehooks'; +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 { Analytics } from '@vercel/analytics/react'; +import ChatwootWidget from 'lib/features/integrations/chatwoot'; + +import 'react-loading-skeleton/dist/skeleton.css'; +import '../../styles/globals.css'; + +import { useRecoilState, useRecoilValue } from 'recoil'; +import { fullWidthState } from '@app/stores/fullWidth'; +import { ChevronDown } from 'lucide-react'; +import HeaderTabs from '@components/pages/main/header-tabs'; +import { headerTabs } from '@app/stores/header-tabs'; +import { usePathname } from 'next/navigation'; + +function MainPage() { + const t = useTranslations(); + const { isTeamMember, isTrackingEnabled, activeTeam } = useOrganizationTeams(); + const fullWidth = useRecoilValue(fullWidthState); + const [view, setView] = useRecoilState(headerTabs); + const path = usePathname(); + const breadcrumb = [ + { title: JSON.parse(t('pages.home.BREADCRUMB')), href: '/' }, + { title: activeTeam?.name || '', href: '/' }, + { title: t(`common.${view}`), href: `/` } + ]; + const { online } = useNetworkState(); + console.log(path, 'path'); + useEffect(() => { + if (view == IssuesView.KANBAN && path == '/') { + setView(IssuesView.CARDS); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [path, setView]); + if (!online) { + return ; + } + return ( + <> + + + +
+
+ + +
+
+ +
+
+ + + +
+ +
+ + {isTeamMember ? : null} + {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 ( + + +
setShowInput((p) => !p)} + className="border dark:border-[#26272C] w-full rounded p-2 md:hidden flex justify-center mt-2" + > + + {showInput ? 'hide the issue input' : 'show the issue input'} + +
+ {isTrackingEnabled ? ( +
+ +
+ ) : null} +
+ ); +} + +export default withAuthentication(MainPage, { displayName: 'MainPage' }); diff --git a/apps/web/app/[locale]/page.tsx b/apps/web/app/[locale]/page.tsx index 6c2818a3d..d14938210 100644 --- a/apps/web/app/[locale]/page.tsx +++ b/apps/web/app/[locale]/page.tsx @@ -1,141 +1,10 @@ -/* eslint-disable no-mixed-spaces-and-tabs */ +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import MainPage from './page-component'; -'use client'; - -import React, { useEffect } 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 } 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 { IssuesView } from '@app/constants'; -import { useNetworkState } from '@uidotdev/usehooks'; -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 { Analytics } from '@vercel/analytics/react'; -import ChatwootWidget from 'lib/features/integrations/chatwoot'; - -import 'react-loading-skeleton/dist/skeleton.css'; -import '../../styles/globals.css'; - -import { useRecoilState, useRecoilValue } from 'recoil'; -import { fullWidthState } from '@app/stores/fullWidth'; -import { ChevronDown } from 'lucide-react'; -import HeaderTabs from '@components/pages/main/header-tabs'; -import { headerTabs } from '@app/stores/header-tabs'; -import { usePathname } from 'next/navigation'; - -function MainPage() { - const t = useTranslations(); - const { isTeamMember, isTrackingEnabled, activeTeam } = useOrganizationTeams(); - const fullWidth = useRecoilValue(fullWidthState); - const [view, setView] = useRecoilState(headerTabs); - const path = usePathname(); - const breadcrumb = [ - { title: JSON.parse(t('pages.home.BREADCRUMB')), href: '/' }, - { title: activeTeam?.name || '', href: '/' }, - { title: t(`common.${view}`), href: `/` } - ]; - const { online } = useNetworkState(); - console.log(path, 'path'); - useEffect(() => { - if (view == IssuesView.KANBAN && path == '/') { - setView(IssuesView.CARDS); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [path, setView]); - if (!online) { - return ; - } - return ( - <> - - - -
-
- - -
-
- -
-
- - - -
- -
- - {isTeamMember ? : null} - {view === IssuesView.CARDS && isTeamMember ? ( - - ) : view === IssuesView.BLOCKS ? ( - - ) : view === IssuesView.TABLE ? ( - - ) : null} - - - {/* Divider */} -
-
- - - {isTeamMember ? : } - -
- - - - ); +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; } -function TaskTimerSection({ isTrackingEnabled }: { isTrackingEnabled: boolean }) { - const [showInput, setShowInput] = React.useState(false); - return ( - - -
setShowInput((p) => !p)} - className="border dark:border-[#26272C] w-full rounded p-2 md:hidden flex justify-center mt-2" - > - - {showInput ? 'hide the issue input' : 'show the issue input'} - -
- {isTrackingEnabled ? ( -
- -
- ) : null} -
- ); +export default function Page() { + return ; } -export default withAuthentication(MainPage, { displayName: 'MainPage' }); diff --git a/apps/web/app/[locale]/permissions/component.tsx b/apps/web/app/[locale]/permissions/component.tsx new file mode 100644 index 000000000..39e802d77 --- /dev/null +++ b/apps/web/app/[locale]/permissions/component.tsx @@ -0,0 +1,293 @@ +'use client'; + +import { useIsMemberManager, useOrganizationTeams, useRolePermissions } from '@app/hooks'; +import { useRoles } from '@app/hooks/features/useRoles'; +import { IRole } from '@app/interfaces'; +import { userState } from '@app/stores'; +import NotFound from '@components/pages/404'; +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 { useTranslations } from 'next-intl'; +import { useRecoilState, useRecoilValue } from 'recoil'; + +import { fullWidthState } from '@app/stores/fullWidth'; + +const Permissions = () => { + const t = useTranslations(); + const { activeTeamManagers } = useOrganizationTeams(); + const { rolePermissionsFormated, getRolePermissions, updateRolePermission } = useRolePermissions(); + + const [selectedRole, setSelectedRole] = useState(null); + const fullWidth = useRecoilValue(fullWidthState); + + const [user] = useRecoilState(userState); + const { isTeamManager } = useIsMemberManager(user); + + useEffect(() => { + selectedRole && selectedRole?.id && getRolePermissions(selectedRole.id); + }, [selectedRole, getRolePermissions]); + + const { getRoles, roles } = useRoles(); + useEffect(() => { + getRoles(); + }, [getRoles]); + + const handleToggleRolePermission = useCallback( + (name: string) => { + const permission = rolePermissionsFormated[name]; + + updateRolePermission({ + ...permission, + enabled: !permission.enabled + }).then(() => { + selectedRole && selectedRole?.id && getRolePermissions(selectedRole.id); + }); + }, + [rolePermissionsFormated, selectedRole, getRolePermissions, updateRolePermission] + ); + + if (activeTeamManagers && activeTeamManagers.length && !isTeamManager) { + return ( + + + + ); + } + + return ( + + + + + + +
+ {roles.map((role) => ( +
{ + setSelectedRole(role); + }} + > + {role?.name} +
+ ))} +
+ + + +
+ {selectedRole && ( +
+
+ + {t('pages.settingsTeam.TRACK_TIME')} + +
+ { + handleToggleRolePermission('TIME_TRACKER'); + }} + /> +
+
+
+ + Estimate issue + +
+ { + handleToggleRolePermission('ORG_TASK_ADD'); + handleToggleRolePermission('ORG_TASK_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.EPICS_CREATE_CLOSE')} + +
+ { + handleToggleRolePermission('ORG_TASK_ADD'); + handleToggleRolePermission('ORG_TASK_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.ISSUE_CREATE_CLOSE')} + +
+ { + handleToggleRolePermission('ORG_TASK_ADD'); + handleToggleRolePermission('ORG_TASK_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.ISSUE_ASSIGN_UNASSIGN')} + +
+ { + handleToggleRolePermission('ORG_TASK_ADD'); + handleToggleRolePermission('ORG_TASK_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.INVITE_MEMBERS')} + +
+ { + handleToggleRolePermission('ORG_INVITE_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.REMOVE_MEMBERS')} + +
+ { + handleToggleRolePermission('ORG_EMPLOYEES_EDIT'); + handleToggleRolePermission('CHANGE_SELECTED_EMPLOYEE'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.HANDLE_REQUESTS')} + +
+ { + handleToggleRolePermission('ORG_TEAM_JOIN_REQUEST_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.ROLES_POSITIONS_CHANGE')} + +
+ { + handleToggleRolePermission('ORG_EMPLOYEES_EDIT'); + }} + /> +
+
+
+ + {t('pages.settingsTeam.VIEW_DETAILS')} + +
+ { + handleToggleRolePermission('ORG_TASK_VIEW'); + }} + /> +
+
+
+ )} + {!selectedRole && } +
+
+
+
+ ); +}; + +function SelectRole() { + return ( +
+
+ ! +
+ + + Please Select any Role + +
+ ); +} + +export default withAuthentication(Permissions, { + displayName: 'PermissionPage' +}); diff --git a/apps/web/app/[locale]/permissions/page.tsx b/apps/web/app/[locale]/permissions/page.tsx index 39e802d77..3cb2520a5 100644 --- a/apps/web/app/[locale]/permissions/page.tsx +++ b/apps/web/app/[locale]/permissions/page.tsx @@ -1,293 +1,10 @@ -'use client'; +import { APPLICATION_DEFAULT_LANGUAGE } from '@app/constants'; +import PermissionPage from './component'; -import { useIsMemberManager, useOrganizationTeams, useRolePermissions } from '@app/hooks'; -import { useRoles } from '@app/hooks/features/useRoles'; -import { IRole } from '@app/interfaces'; -import { userState } from '@app/stores'; -import NotFound from '@components/pages/404'; -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 { useTranslations } from 'next-intl'; -import { useRecoilState, useRecoilValue } from 'recoil'; - -import { fullWidthState } from '@app/stores/fullWidth'; - -const Permissions = () => { - const t = useTranslations(); - const { activeTeamManagers } = useOrganizationTeams(); - const { rolePermissionsFormated, getRolePermissions, updateRolePermission } = useRolePermissions(); - - const [selectedRole, setSelectedRole] = useState(null); - const fullWidth = useRecoilValue(fullWidthState); - - const [user] = useRecoilState(userState); - const { isTeamManager } = useIsMemberManager(user); - - useEffect(() => { - selectedRole && selectedRole?.id && getRolePermissions(selectedRole.id); - }, [selectedRole, getRolePermissions]); - - const { getRoles, roles } = useRoles(); - useEffect(() => { - getRoles(); - }, [getRoles]); - - const handleToggleRolePermission = useCallback( - (name: string) => { - const permission = rolePermissionsFormated[name]; - - updateRolePermission({ - ...permission, - enabled: !permission.enabled - }).then(() => { - selectedRole && selectedRole?.id && getRolePermissions(selectedRole.id); - }); - }, - [rolePermissionsFormated, selectedRole, getRolePermissions, updateRolePermission] - ); - - if (activeTeamManagers && activeTeamManagers.length && !isTeamManager) { - return ( - - - - ); - } - - return ( - - - - - - -
- {roles.map((role) => ( -
{ - setSelectedRole(role); - }} - > - {role?.name} -
- ))} -
- - - -
- {selectedRole && ( -
-
- - {t('pages.settingsTeam.TRACK_TIME')} - -
- { - handleToggleRolePermission('TIME_TRACKER'); - }} - /> -
-
-
- - Estimate issue - -
- { - handleToggleRolePermission('ORG_TASK_ADD'); - handleToggleRolePermission('ORG_TASK_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.EPICS_CREATE_CLOSE')} - -
- { - handleToggleRolePermission('ORG_TASK_ADD'); - handleToggleRolePermission('ORG_TASK_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.ISSUE_CREATE_CLOSE')} - -
- { - handleToggleRolePermission('ORG_TASK_ADD'); - handleToggleRolePermission('ORG_TASK_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.ISSUE_ASSIGN_UNASSIGN')} - -
- { - handleToggleRolePermission('ORG_TASK_ADD'); - handleToggleRolePermission('ORG_TASK_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.INVITE_MEMBERS')} - -
- { - handleToggleRolePermission('ORG_INVITE_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.REMOVE_MEMBERS')} - -
- { - handleToggleRolePermission('ORG_EMPLOYEES_EDIT'); - handleToggleRolePermission('CHANGE_SELECTED_EMPLOYEE'); - }} - /> -
-
-
- - {t('pages.settingsTeam.HANDLE_REQUESTS')} - -
- { - handleToggleRolePermission('ORG_TEAM_JOIN_REQUEST_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.ROLES_POSITIONS_CHANGE')} - -
- { - handleToggleRolePermission('ORG_EMPLOYEES_EDIT'); - }} - /> -
-
-
- - {t('pages.settingsTeam.VIEW_DETAILS')} - -
- { - handleToggleRolePermission('ORG_TASK_VIEW'); - }} - /> -
-
-
- )} - {!selectedRole && } -
-
-
-
- ); -}; - -function SelectRole() { - return ( -
-
- ! -
- - - Please Select any Role - -
- ); +export default function Page() { + return ; } -export default withAuthentication(Permissions, { - displayName: 'PermissionPage' -}); +export async function generateStaticParams() { + return [{ locale: APPLICATION_DEFAULT_LANGUAGE }]; +} diff --git a/apps/web/app/api/image-assets/upload/[folder]/route.ts b/apps/web/app/api/image-assets/upload/[folder]/route.ts index c075fd57b..449d7d5a8 100644 --- a/apps/web/app/api/image-assets/upload/[folder]/route.ts +++ b/apps/web/app/api/image-assets/upload/[folder]/route.ts @@ -5,13 +5,16 @@ import { INextParams } from '@app/interfaces'; export async function POST(req: Request, { params }: INextParams) { const res = new NextResponse(); + const folderParam = params.folder; + + if (!folderParam) { + return; + } const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return NextResponse.json({}, { status: 401 }); - const folderParam = params.folder as string; - const form = await req.formData(); const response = await createImageAssetsRequest( diff --git a/apps/web/app/api/integration-tenant/[id]/route.ts b/apps/web/app/api/integration-tenant/[id]/route.ts index 240d97b26..63939f7d5 100644 --- a/apps/web/app/api/integration-tenant/[id]/route.ts +++ b/apps/web/app/api/integration-tenant/[id]/route.ts @@ -1,17 +1,20 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteIntegrationTenantRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + const integrationId = params.id; + + if (!integrationId) { + return; + } + const { $res, user, access_token, tenantId, organizationId } = await authenticatedGuard(req, res); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const { id } = params; + const response = await deleteIntegrationTenantRequest(integrationId, tenantId, organizationId, access_token); - if (id) { - const response = await deleteIntegrationTenantRequest(id as string, tenantId, organizationId, access_token); - - return $res(response.data); - } + return $res(response.data); } diff --git a/apps/web/app/api/invite/[id]/route.ts b/apps/web/app/api/invite/[id]/route.ts index 8aa06b6f1..ad8204836 100644 --- a/apps/web/app/api/invite/[id]/route.ts +++ b/apps/web/app/api/invite/[id]/route.ts @@ -11,13 +11,13 @@ import { NextResponse } from 'next/server'; export async function GET(req: Request, { params }: { params: { id: string } }) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({}, { status: 401 }); - - if (params.id) { + if (!params.id) { return NextResponse.json({}, { status: 400 }); } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + if (!user) return NextResponse.json({}, { status: 401 }); + const { data } = await getMyInvitationsRequest(tenantId, access_token); return $res(data); @@ -25,15 +25,15 @@ export async function GET(req: Request, { params }: { params: { id: string } }) export async function DELETE(req: Request, { params }: { params: { id: string } }) { const res = new NextResponse(); - const { $res, user, access_token, tenantId, organizationId, teamId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({}, { status: 401 }); - const invitationId = params.id; - if (params.id) { + if (!invitationId) { return NextResponse.json({}, { status: 400 }); } + const { $res, user, access_token, tenantId, organizationId, teamId } = await authenticatedGuard(req, res); + if (!user) return NextResponse.json({}, { status: 401 }); + await removeTeamInvitationsRequest({ bearer_token: access_token, tenantId: tenantId, @@ -63,7 +63,7 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) const { searchParams } = new URL(req.url); const { action } = searchParams as unknown as { action: string }; - if (params.id) { + if (!invitationId) { return NextResponse.json({}, { status: 400 }); } diff --git a/apps/web/app/api/issue-types/[id]/route.ts b/apps/web/app/api/issue-types/[id]/route.ts index adc5bef54..133aa941a 100644 --- a/apps/web/app/api/issue-types/[id]/route.ts +++ b/apps/web/app/api/issue-types/[id]/route.ts @@ -1,18 +1,22 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteIssueTypesRequest, editIssueTypesRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const { id } = params; const body = await req.json(); const response = await editIssueTypesRequest({ - id, + id: params.id, datas: body, bearer_token: access_token, tenantId @@ -21,16 +25,18 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const { id } = params; - const response = await deleteIssueTypesRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/organization-projects/[id]/route.ts b/apps/web/app/api/organization-projects/[id]/route.ts index 0b2242eb3..072bf41d9 100644 --- a/apps/web/app/api/organization-projects/[id]/route.ts +++ b/apps/web/app/api/organization-projects/[id]/route.ts @@ -5,16 +5,18 @@ import { NextResponse } from 'next/server'; export async function PUT(req: Request, { params }: { params: { id: string } }) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const { id } = params; - const body = await req.json(); const response = await editOrganizationProjectsRequest({ bearer_token: access_token, - id, + id: params.id, datas: body, tenantId }); diff --git a/apps/web/app/api/organization-projects/setting/[id]/route.ts b/apps/web/app/api/organization-projects/setting/[id]/route.ts index 830715142..ab96a8a0c 100644 --- a/apps/web/app/api/organization-projects/setting/[id]/route.ts +++ b/apps/web/app/api/organization-projects/setting/[id]/route.ts @@ -1,19 +1,24 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { editOrganizationProjectsSettingsRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const { id } = params; const body = await req.json(); const response = await editOrganizationProjectsSettingsRequest({ + id: params.id, bearer_token: access_token, - id, datas: body, tenantId }); diff --git a/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts b/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts index 5857a8804..58e6592b1 100644 --- a/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts +++ b/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts @@ -1,24 +1,27 @@ -import { IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; +import { INextParams, IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { updateOrganizationTeamEmployeeActiveTaskRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + if (!user) return NextResponse.json({ error: 'unauthorized' }, { status: 401 }); - const { id } = params; const body = (await req.json()) as IOrganizationTeamEmployeeUpdate; - if (id) { - const response = await updateOrganizationTeamEmployeeActiveTaskRequest({ - id: id as string, - bearer_token: access_token, - tenantId, - body - }); + const response = await updateOrganizationTeamEmployeeActiveTaskRequest({ + id: params.id, + bearer_token: access_token, + tenantId, + body + }); - return $res(response.data); - } + return $res(response.data); } diff --git a/apps/web/app/api/organization-team-employee/[id]/route.ts b/apps/web/app/api/organization-team-employee/[id]/route.ts index 1d5b2e580..0940d00e7 100644 --- a/apps/web/app/api/organization-team-employee/[id]/route.ts +++ b/apps/web/app/api/organization-team-employee/[id]/route.ts @@ -1,4 +1,4 @@ -import { IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; +import { INextParams, IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteOrganizationTeamEmployeeRequest, @@ -6,47 +6,52 @@ import { } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + if (!user) return $res('Unauthorized'); const body = (await req.json()) as IOrganizationTeamEmployeeUpdate; - const { id } = params; - const response = await updateOrganizationTeamEmployeeRequest({ - id: id as string, + id: params.id, bearer_token: access_token, tenantId, body: body }); - if (id) { - return $res(response.data); - } + return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId, organizationId, teamId } = await authenticatedGuard(req, res); + if (!user) return $res('Unauthorized'); const { searchParams } = new URL(req.url); - const { employeeId } = searchParams as unknown as { employeeId: string }; - const { id } = params; + const employeeId = searchParams.get('employeeId') as string; const response = await deleteOrganizationTeamEmployeeRequest({ - id: id as string, + id: params.id, bearer_token: access_token, tenantId, organizationId, - employeeId: employeeId as string, + employeeId: employeeId, organizationTeamId: teamId }); - if (id) { - return $res(response.data); - } + return $res(response.data); } diff --git a/apps/web/app/api/organization-team-join/[id]/[action]/route.ts b/apps/web/app/api/organization-team-join/[id]/[action]/route.ts index 251f06eb0..231e673d0 100644 --- a/apps/web/app/api/organization-team-join/[id]/[action]/route.ts +++ b/apps/web/app/api/organization-team-join/[id]/[action]/route.ts @@ -1,23 +1,25 @@ -import { IRequestToJoinActionEnum } from '@app/interfaces'; +import { INextParams, IRequestToJoinActionEnum } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { acceptRejectRequestToJoinRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string; action: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id || !params.action) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('unauthorized'); - const { id, action } = params; + if (!user) return $res('unauthorized'); - if (id) { - const response = await acceptRejectRequestToJoinRequest({ - id: id as string, - bearer_token: access_token, - tenantId, - action: action as IRequestToJoinActionEnum - }); + const response = await acceptRejectRequestToJoinRequest({ + id: params.id, + bearer_token: access_token, + tenantId, + action: params.action as IRequestToJoinActionEnum + }); - return $res(response.data); - } + return $res(response.data); } diff --git a/apps/web/app/api/organization-team/[id]/route.ts b/apps/web/app/api/organization-team/[id]/route.ts index d7b40d03b..859e621da 100644 --- a/apps/web/app/api/organization-team/[id]/route.ts +++ b/apps/web/app/api/organization-team/[id]/route.ts @@ -1,3 +1,4 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { @@ -7,67 +8,73 @@ import { } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function GET(req: Request) { +export async function GET(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, organizationId, access_token, tenantId, teamId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({}, { status: 400 }); - const getTeamStatus = async () => { - const { data: team } = await getOrganizationTeamRequest( - { - organizationId, - tenantId, - teamId: teamId - }, - access_token - ); + if (!user) return NextResponse.json({}, { status: 400 }); - return team; - }; + const { data } = await getOrganizationTeamRequest( + { + organizationId, + tenantId, + teamId: teamId + }, + access_token + ); - return $res(await getTeamStatus()); + return $res(data); } -export async function PUT(req: Request) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, organizationId, access_token, tenantId, teamId } = await authenticatedGuard(req, res); + if (!user) return NextResponse.json({}, { status: 400 }); const body = await req.json(); - const getTeamStatus = async () => { - const { data: team } = await getOrganizationTeamRequest( - { - organizationId, - tenantId, - teamId: teamId - }, - access_token - ); - - return team; - }; + const { data } = await getOrganizationTeamRequest( + { + organizationId, + tenantId, + teamId: teamId + }, + access_token + ); await updateOrganizationTeamRequest(body, access_token); - return $res(await getTeamStatus()); + return $res(data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, organizationId, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({}, { status: 400 }); - const { id } = params; + if (!user) return NextResponse.json({}, { status: 400 }); - if (id) { - const response = await deleteOrganizationTeamRequest({ - id: id as string, - bearer_token: access_token, - tenantId, - organizationId - }); + const response = await deleteOrganizationTeamRequest({ + id: params.id, + bearer_token: access_token, + tenantId, + organizationId + }); - return $res(response.data); - } + return $res(response.data); } diff --git a/apps/web/app/api/organization-team/employee/[id]/route.ts b/apps/web/app/api/organization-team/employee/[id]/route.ts index e2ccbf950..ef073312e 100644 --- a/apps/web/app/api/organization-team/employee/[id]/route.ts +++ b/apps/web/app/api/organization-team/employee/[id]/route.ts @@ -1,3 +1,4 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { addEmployeeOrganizationTeamOrderRequest, @@ -5,44 +6,45 @@ import { } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({}, { status: 401 }); - const { id } = params; - - if (!id) { + if (!params.id) { return NextResponse.json({}, { status: 405 }); } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + + if (!user) return NextResponse.json({}, { status: 401 }); + const response = await removeEmployeeOrganizationTeamRequest({ bearer_token: access_token, tenantId, - employeeId: id.toString() + employeeId: params.id }); return $res(response.data); } -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return NextResponse.json({}, { status: 405 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + if (!user) return NextResponse.json({}, { status: 401 }); const body = await req.json(); - const { id } = params; const order = body.order; - if (!id) { - return NextResponse.json({}, { status: 405 }); - } - const response = await addEmployeeOrganizationTeamOrderRequest({ bearer_token: access_token, + employeeId: params.id, tenantId, - employeeId: id.toString(), order, organizationTeamId: body.organizationTeamId, organizationId: body.organizationId diff --git a/apps/web/app/api/organization-team/teams/[id]/route.ts b/apps/web/app/api/organization-team/teams/[id]/route.ts index 534da9d44..99b3fb650 100644 --- a/apps/web/app/api/organization-team/teams/[id]/route.ts +++ b/apps/web/app/api/organization-team/teams/[id]/route.ts @@ -1,19 +1,24 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { removeUserFromAllTeam } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({}, { status: 401 }); - const { id } = params; + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!id) return NextResponse.json({}, { status: 400 }); + if (!user) { + return NextResponse.json({}, { status: 401 }); + } const response = await removeUserFromAllTeam({ - userId: id as string, + userId: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/public/team/[profileLink]/[teamId]/route.ts b/apps/web/app/api/public/team/[profileLink]/[teamId]/route.ts index 861839fe0..8b1227b78 100644 --- a/apps/web/app/api/public/team/[profileLink]/[teamId]/route.ts +++ b/apps/web/app/api/public/team/[profileLink]/[teamId]/route.ts @@ -1,27 +1,32 @@ +import { INextParams } from '@app/interfaces'; import { getPublicOrganizationTeamMiscDataRequest, getPublicOrganizationTeamRequest } from '@app/services/server/requests/public-organization-team'; import { NextResponse } from 'next/server'; -export async function GET(req: Request, { params }: { params: { profileLink: string; teamId: string } }) { +export async function GET(req: Request, { params }: INextParams) { const { searchParams } = new URL(req.url); - const { profileLink, teamId } = params; - const { type } = searchParams as unknown as { type: string }; + if (!params.profileLink || !params.teamId) { + return; + } + + const type = searchParams.get('type') as string; if (type === 'misc') { const response = await getPublicOrganizationTeamMiscDataRequest({ - profileLink: profileLink, - teamId + profileLink: params.profileLink, + teamId: params.teamId }); return NextResponse.json(response.data); } const response = await getPublicOrganizationTeamRequest({ - profileLink: profileLink, - teamId + profileLink: params.profileLink, + teamId: params.teamId }); + return NextResponse.json(response.data); } diff --git a/apps/web/app/api/role-permissions/[id]/route.ts b/apps/web/app/api/role-permissions/[id]/route.ts index 6ceb4941c..ac15e3d36 100644 --- a/apps/web/app/api/role-permissions/[id]/route.ts +++ b/apps/web/app/api/role-permissions/[id]/route.ts @@ -1,26 +1,35 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { getRolePermissionsRequest, updateRolePermissionRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function GET(req: Request, { params }: { params: { id: string } }) { +export async function GET(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('unauthorized'); - const { id } = params; - const response = await getRolePermissionsRequest({ + roleId: params.id, bearer_token: access_token, - tenantId, - roleId: id as string + tenantId }); return $res(response.data); } -export async function PUT(req: Request) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('unauthorized'); diff --git a/apps/web/app/api/roles/[id]/route.ts b/apps/web/app/api/roles/[id]/route.ts index 94bf659bc..5f6283bc0 100644 --- a/apps/web/app/api/roles/[id]/route.ts +++ b/apps/web/app/api/roles/[id]/route.ts @@ -1,10 +1,15 @@ -import { IRole } from '@app/interfaces'; +import { INextParams, IRole } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteRoleRequest, updateRoleRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('unauthorized'); @@ -19,17 +24,19 @@ export async function PUT(req: Request) { return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('unauthorized'); - const { id } = params; - const response = await deleteRoleRequest({ - id: id as string, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/tags/[id]/route.ts b/apps/web/app/api/tags/[id]/route.ts index 2b676f239..d448a4716 100644 --- a/apps/web/app/api/tags/[id]/route.ts +++ b/apps/web/app/api/tags/[id]/route.ts @@ -1,18 +1,23 @@ -import { ITaskLabelsCreate } from '@app/interfaces'; +import { INextParams, ITaskLabelsCreate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteTaskLabelsRequest, editTaskLabelsRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({ error: 'unauthorized' }, { status: 401 }); + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - const { id } = params; + if (!user) { + return NextResponse.json({ error: 'unauthorized' }, { status: 401 }); + } const response = await deleteTaskLabelsRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); @@ -20,17 +25,23 @@ export async function DELETE(req: Request, { params }: { params: { id: string } return $res(response.data); } -export async function PUT(req: Request, { params }: { params: { id: string } }) { - const body = (await req.json()) as unknown as ITaskLabelsCreate; +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return NextResponse.json({ error: 'unauthorized' }, { status: 401 }); + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + + const body = (await req.json()) as unknown as ITaskLabelsCreate; + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - const { id } = params; + if (!user) { + return NextResponse.json({ error: 'unauthorized' }, { status: 401 }); + } const response = await editTaskLabelsRequest({ - id, + id: params.id, datas: body, bearer_token: access_token, tenantId diff --git a/apps/web/app/api/task-priorities/[id]/route.ts b/apps/web/app/api/task-priorities/[id]/route.ts index 94f779cc2..49b036d4d 100644 --- a/apps/web/app/api/task-priorities/[id]/route.ts +++ b/apps/web/app/api/task-priorities/[id]/route.ts @@ -1,38 +1,44 @@ -import { ITaskPrioritiesCreate } from '@app/interfaces'; +import { INextParams, ITaskPrioritiesCreate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteTaskPrioritiesRequest, editTaskPrioritiesRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('Unauthorized'); - const { id } = params; - const datas = (await req.json()) as unknown as ITaskPrioritiesCreate; const response = await editTaskPrioritiesRequest({ - id, - datas, + id: params.id, bearer_token: access_token, + datas, tenantId }); return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return NextResponse.json({}, { status: 400 }); + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('Unauthorized'); - const { id } = params; - const response = await deleteTaskPrioritiesRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/task-related-issue-types/[id]/route.ts b/apps/web/app/api/task-related-issue-types/[id]/route.ts index c8b3245a4..53af6b037 100644 --- a/apps/web/app/api/task-related-issue-types/[id]/route.ts +++ b/apps/web/app/api/task-related-issue-types/[id]/route.ts @@ -1,4 +1,4 @@ -import { ITaskRelatedIssueTypeCreate } from '@app/interfaces'; +import { INextParams, ITaskRelatedIssueTypeCreate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteTaskRelatedIssueTypeRequest, @@ -6,36 +6,46 @@ import { } from '@app/services/server/requests/task-related-issue-type'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + if (!params.id) { + return; + } + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - const { id } = params; + if (!user) { + return $res('Unauthorized'); + } const datas = (await req.json()) as unknown as ITaskRelatedIssueTypeCreate; const response = await editTaskRelatedIssueTypeRequest({ - id, - datas, + id: params.id, bearer_token: access_token, + datas, tenantId }); return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + if (!params.id) { + return; + } + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - const { id } = params; + if (!user) { + return $res('Unauthorized'); + } const response = await deleteTaskRelatedIssueTypeRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/task-sizes/[id]/route.ts b/apps/web/app/api/task-sizes/[id]/route.ts index ab9644f12..70e96809d 100644 --- a/apps/web/app/api/task-sizes/[id]/route.ts +++ b/apps/web/app/api/task-sizes/[id]/route.ts @@ -1,38 +1,46 @@ -import { ITaskSizesCreate } from '@app/interfaces'; +import { INextParams, ITaskSizesCreate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteTaskSizesRequest, editTaskSizesRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + if (!params.id) { + return; + } - const { id } = params; + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + + if (!user) { + return $res('Unauthorized'); + } const datas = (await req.json()) as unknown as ITaskSizesCreate; const response = await editTaskSizesRequest({ - id, - datas, + id: params.id, bearer_token: access_token, + datas, tenantId }); return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('Unauthorized'); - const { id } = params; - const response = await deleteTaskSizesRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/task-statuses/[id]/route.ts b/apps/web/app/api/task-statuses/[id]/route.ts index 2d60edab8..df5ef1e4f 100644 --- a/apps/web/app/api/task-statuses/[id]/route.ts +++ b/apps/web/app/api/task-statuses/[id]/route.ts @@ -1,38 +1,46 @@ -import { ITaskStatusCreate } from '@app/interfaces'; +import { INextParams, ITaskStatusCreate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteTaskStatusRequest, editTaskStatusRequest } from '@app/services/server/requests/taskStatus'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('Unauthorized'); - const { id } = params; - - const datas = (await req.json()) as unknown as ITaskStatusCreate; + const datas = (await req.json()) as ITaskStatusCreate; const response = await editTaskStatusRequest({ - id, - datas, + id: params.id, bearer_token: access_token, + datas, tenantId }); return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + if (!params.id) { + return; + } + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - const { id } = params; + if (!user) { + return $res('Unauthorized'); + } const response = await deleteTaskStatusRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/task-versions/[id]/route.ts b/apps/web/app/api/task-versions/[id]/route.ts index aad09ccbf..4620c4010 100644 --- a/apps/web/app/api/task-versions/[id]/route.ts +++ b/apps/web/app/api/task-versions/[id]/route.ts @@ -1,38 +1,46 @@ -import { ITaskVersionCreate } from '@app/interfaces'; +import { INextParams, ITaskVersionCreate } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteTaskVersionRequest, editTaskVersionRequest } from '@app/services/server/requests/task-version'; import { NextResponse } from 'next/server'; -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('Unauthorized'); - const { id } = params; - - const datas = (await req.json()) as unknown as ITaskVersionCreate; + const datas = (await req.json()) as ITaskVersionCreate; const response = await editTaskVersionRequest({ - id, - datas, + id: params.id, bearer_token: access_token, + datas, tenantId }); return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { id: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); - const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + if (!params.id) { + return; + } + + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - const { id } = params; + if (!user) { + return $res('Unauthorized'); + } const response = await deleteTaskVersionRequest({ - id, + id: params.id, bearer_token: access_token, tenantId }); diff --git a/apps/web/app/api/tasks/[id]/route.ts b/apps/web/app/api/tasks/[id]/route.ts index 84f6721fb..b2ffebbf4 100644 --- a/apps/web/app/api/tasks/[id]/route.ts +++ b/apps/web/app/api/tasks/[id]/route.ts @@ -1,17 +1,21 @@ +import { INextParams } from '@app/interfaces'; import { ITeamTask } from '@app/interfaces/ITask'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { getTeamTasksRequest, updateTaskRequest, getTaskByIdRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function GET(req: Request, { params }: { params: { id: string } }) { +export async function GET(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, tenantId, access_token, organizationId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); - const { id: taskId } = params; + if (!user) return $res('Unauthorized'); const response = await getTaskByIdRequest({ - taskId: taskId as string, + taskId: params.id, tenantId, organizationId, bearer_token: access_token @@ -20,16 +24,20 @@ export async function GET(req: Request, { params }: { params: { id: string } }) return $res(response.data); } -export async function PUT(req: Request, { params }: { params: { id: string } }) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, tenantId, access_token, organizationId, projectId, teamId } = await authenticatedGuard( req, res ); + if (!user) return $res('Unauthorized'); - const { id: taskId } = params; - const body = (await req.json()) as unknown as ITeamTask; + const body = (await req.json()) as ITeamTask; delete body.selectedTeam; delete body.rootEpic; @@ -37,7 +45,7 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) await updateTaskRequest( { data: body, - id: taskId as string + id: params.id }, access_token ); diff --git a/apps/web/app/api/tasks/employee/[employeeId]/route.ts b/apps/web/app/api/tasks/employee/[employeeId]/route.ts index 265cec263..dd7f50048 100644 --- a/apps/web/app/api/tasks/employee/[employeeId]/route.ts +++ b/apps/web/app/api/tasks/employee/[employeeId]/route.ts @@ -1,45 +1,56 @@ +import { INextParams } from '@app/interfaces'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { deleteEmployeeFromTasksRequest, getEmployeeTasksRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function GET(req: Request, { params }: { params: { employeeId: string } }) { +export async function GET(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.employeeId) { + return; + } + const { $res, user, tenantId, access_token: bearer_token } = await authenticatedGuard(req, res); + if (!user) return $res('Unauthorized'); const { searchParams } = new URL(req.url); - const { employeeId } = params; const { organizationTeamId } = searchParams as unknown as { organizationTeamId: string; }; const response = await getEmployeeTasksRequest({ - tenantId, - employeeId, + employeeId: params.employeeId, organizationTeamId, + tenantId, bearer_token }); return $res(response.data); } -export async function DELETE(req: Request, { params }: { params: { employeeId: string } }) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + + if (!params.employeeId) { + return; + } + const { $res, user, tenantId, access_token: bearer_token } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + + if (!user) { + return $res('Unauthorized'); + } const { searchParams } = new URL(req.url); - const { employeeId } = params; - const { organizationTeamId } = searchParams as unknown as { - organizationTeamId: string; - }; + const organizationTeamId = searchParams.get('organizationTeamId') as string; const response = await deleteEmployeeFromTasksRequest({ - tenantId, - employeeId, + employeeId: params.employeeId, organizationTeamId, + tenantId, bearer_token }); diff --git a/apps/web/app/api/user/[id]/route.ts b/apps/web/app/api/user/[id]/route.ts index 93e85f7c9..dcdd894d3 100644 --- a/apps/web/app/api/user/[id]/route.ts +++ b/apps/web/app/api/user/[id]/route.ts @@ -1,30 +1,43 @@ +import { INextParams } from '@app/interfaces'; import { IUser } from '@app/interfaces/IUserData'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; import { getTaskCreator, updateUserAvatarRequest } from '@app/services/server/requests'; import { deleteUserRequest } from '@app/services/server/requests/user'; import { NextResponse } from 'next/server'; -export async function GET(req: Request, { params }: { params: { id: string } }) { +export async function GET(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, access_token } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); - const { id: userId } = params; + if (!user) { + return $res('Unauthorized'); + } const { data } = await getTaskCreator({ - userId: userId as string, + userId: params.id, bearer_token: access_token }); return $res(data); } -export async function PUT(req: Request) { +export async function PUT(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + + if (!user) { + return $res('Unauthorized'); + } const body = (await req.json()) as unknown as IUser; @@ -40,11 +53,18 @@ export async function PUT(req: Request) { return $res(response.data); } -export async function DELETE(req: Request) { +export async function DELETE(req: Request, { params }: INextParams) { const res = new NextResponse(); + if (!params.id) { + return; + } + const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); - if (!user) return $res('Unauthorized'); + + if (!user) { + return $res('Unauthorized'); + } const response = await deleteUserRequest({ id: user.id, diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 887f56013..5cffc679d 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -152,6 +152,9 @@ export const APPLICATION_LANGUAGES = [ 'Russian', 'Spanish' ]; + +export const APPLICATION_DEFAULT_LANGUAGE = 'en'; + export const APPLICATION_LANGUAGES_CODE = [ 'en', 'fr', diff --git a/apps/web/app/hooks/auth/useAuthenticationPasscode.ts b/apps/web/app/hooks/auth/useAuthenticationPasscode.ts index a52d11148..9afd4c064 100644 --- a/apps/web/app/hooks/auth/useAuthenticationPasscode.ts +++ b/apps/web/app/hooks/auth/useAuthenticationPasscode.ts @@ -29,6 +29,7 @@ export function useAuthenticationPasscode() { const queryEmail = useMemo(() => { const emailQuery = query?.get('email') || ''; + if (typeof localStorage !== 'undefined') { localStorage?.setItem('ever-teams-start-email', emailQuery); } diff --git a/apps/web/app/hooks/auth/useAuthenticationTeam.ts b/apps/web/app/hooks/auth/useAuthenticationTeam.ts index 36fa9f926..24d07e9d2 100644 --- a/apps/web/app/hooks/auth/useAuthenticationTeam.ts +++ b/apps/web/app/hooks/auth/useAuthenticationTeam.ts @@ -31,10 +31,17 @@ const initialValues: IRegisterDataAPI = RECAPTCHA_SITE_KEY email: '', team: '' }; + export function useAuthenticationTeam() { const query = useSearchParams(); const queryEmail = useMemo(() => { - const emailQuery = query?.get('email') || localStorage?.getItem('ever-teams-start-email') || ''; + let localEmail: null | string = null; + + if (typeof localStorage !== 'undefined') { + localEmail = localStorage?.getItem('ever-teams-start-email'); + } + + const emailQuery = query?.get('email') || localEmail || ''; return emailQuery; }, [query]); initialValues.email = queryEmail; diff --git a/apps/web/app/hooks/features/useTimeSlot.ts b/apps/web/app/hooks/features/useTimeSlot.ts index e6cbb7c38..d33770836 100644 --- a/apps/web/app/hooks/features/useTimeSlot.ts +++ b/apps/web/app/hooks/features/useTimeSlot.ts @@ -31,9 +31,8 @@ export function useTimeSlots(hasFilter?: boolean) { todayEnd, todayStart }).then((response) => { - if (response.data) { - // @ts-expect-error - setTimeSlots(response.data[0].timeSlots); + if (response.data && Array.isArray(response.data)) { + setTimeSlots(response.data[0]?.timeSlots || []); } }); } else setTimeSlots([]); diff --git a/apps/web/app/services/client/api/task-status.ts b/apps/web/app/services/client/api/task-status.ts index e5f3eecb5..cf4343e5e 100644 --- a/apps/web/app/services/client/api/task-status.ts +++ b/apps/web/app/services/client/api/task-status.ts @@ -1,5 +1,6 @@ import { DeleteResponse, ITaskStatusCreate, ITaskStatusItemList, PaginationResponse } from '@app/interfaces'; import { deleteApi, get, post, put } from '../axios'; +import qs from 'qs'; export function createTaskStatusAPI(data: ITaskStatusCreate, tenantId?: string) { return post('/task-statuses', data, { @@ -18,7 +19,13 @@ export function deleteTaskStatusAPI(id: string) { } export async function getTaskStatusList(tenantId: string, organizationId: string, organizationTeamId: string | null) { - const endpoint = `/task-statuses?tenantId=${tenantId}&organizationId=${organizationId}&organizationTeamId=${organizationTeamId}`; + const query = qs.stringify({ + tenantId, + organizationId, + organizationTeamId + }); + + const endpoint = `/task-statuses?${query}`; return get>(endpoint, { tenantId }); } diff --git a/apps/web/lib/components/Kanban.tsx b/apps/web/lib/components/Kanban.tsx index 14255bc60..1fb2f6a27 100644 --- a/apps/web/lib/components/Kanban.tsx +++ b/apps/web/lib/components/Kanban.tsx @@ -262,7 +262,7 @@ const KanbanDraggableHeader = ({ <> {title && (
diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 4b939b510..cb062985c 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -1,4 +1,5 @@ import { + APPLICATION_DEFAULT_LANGUAGE, DEFAULT_APP_PATH, DEFAULT_MAIN_PATH, PROTECTED_APP_URL_PATHS, @@ -30,7 +31,7 @@ export const config = { export async function middleware(request: NextRequest) { const nextIntlMiddleware = createMiddleware({ - defaultLocale: 'en', + defaultLocale: APPLICATION_DEFAULT_LANGUAGE, locales: ['en', 'de', 'ar', 'bg', 'zh', 'nl', 'de', 'he', 'it', 'pl', 'pt', 'ru', 'es', 'fr'], // pathnames, localePrefix: 'as-needed' diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 547e6654c..a82eec3c3 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -8,6 +8,8 @@ const isProduction = process.env.NODE_ENV === 'production'; const isSentryEnabled = isProduction && process.env.SENTRY_DSN; +const BUILD_OUTPUT_MODE = process.env.NEXT_BUILD_OUTPUT_TYPE; + const sentryConfig = isSentryEnabled && { sentry: { // For all available options, see: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ @@ -31,7 +33,7 @@ const sentryConfig = isSentryEnabled && { // eslint-disable-next-line @typescript-eslint/no-var-requires /** @type {import('next').NextConfig} */ const nextConfig = { - output: process.env.NEXT_BUILD_OUTPUT_TYPE === 'standalone' ? 'standalone' : undefined, + output: ['standalone', 'export'].includes(BUILD_OUTPUT_MODE) ? BUILD_OUTPUT_MODE : undefined, reactStrictMode: false, swcMinify: true, webpack: (config, { isServer }) => {