From 4d05ab0b5b7c6776fc67eb42ca80587c1d73a59a Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Fri, 8 Dec 2023 12:33:54 +0100 Subject: [PATCH 01/34] chore:add interfaces --- .../lib/features/team-members-kanban-view.tsx | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/web/lib/features/team-members-kanban-view.tsx b/apps/web/lib/features/team-members-kanban-view.tsx index da8d4dbf4..6a166e576 100644 --- a/apps/web/lib/features/team-members-kanban-view.tsx +++ b/apps/web/lib/features/team-members-kanban-view.tsx @@ -1,23 +1,25 @@ import { useKanban } from "@app/hooks/features/useKanban"; +import { ITaskStatusItemList, ITeamTask } from "@app/interfaces"; +import { IKanban } from "@app/interfaces/IKanban"; import { clsxm } from "@app/utils"; import KanbanDraggable, { EmptyKanbanDroppable } from "lib/components/Kanban" import { AddIcon } from "lib/components/svgs"; import React from "react"; import { useEffect, useState } from "react"; -import { DragDropContext, DropResult, Droppable, DroppableProvided, DroppableStateSnapshot } from "react-beautiful-dnd"; +import { DragDropContext, DraggableLocation, DropResult, Droppable, DroppableProvided, DroppableStateSnapshot } from "react-beautiful-dnd"; -const reorder = (list: any[], startIndex:number , endIndex:number ) => { +const reorder = (list: ITeamTask[], startIndex:number , endIndex:number ) => { const result = Array.from(list); const [removed] = result.splice(startIndex, 1); result.splice(endIndex, 0, removed); - + return result; }; const reorderItemMap = ({ itemMap, source, destination }: { - itemMap: any, - source: any, - destination: any + itemMap: IKanban, + source: DraggableLocation, + destination: DraggableLocation }) => { const current = [...itemMap[source.droppableId]]; const next = [...itemMap[destination.droppableId]]; @@ -35,8 +37,6 @@ const reorderItemMap = ({ itemMap, source, destination }: { }; } - // moving to different list - // remove from original current.splice(source.index, 1); // insert into next @@ -53,22 +53,22 @@ const reorderItemMap = ({ itemMap, source, destination }: { }; }; -const getHeaderBackground = (columns: any, column: any) => { +const getHeaderBackground = (columns: ITaskStatusItemList[], column: string) => { - const selectState = columns.filter((item: any)=> { + const selectState = columns.filter((item: ITaskStatusItemList)=> { return item.name === column }); return selectState[0].color } -export const KanbanView = ({ itemsArray }: { itemsArray: any}) => { +export const KanbanView = ({ itemsArray }: { itemsArray: IKanban}) => { - const { columns:kanbanColumns } = useKanban(); + const { columns:kanbanColumns, updateKanbanBoard, data:kanbandata } = useKanban(); - const [items, setItems] = useState(itemsArray); - - const [columns, setColumn] = useState(Object.keys(itemsArray)); + const [items, setItems] = useState(itemsArray); + + const [columns, setColumn] = useState(Object.keys(itemsArray)); /** * This function handles all drag and drop logic @@ -96,6 +96,7 @@ export const KanbanView = ({ itemsArray }: { itemsArray: any}) => { [result.source.droppableId]: withItemRemoved, }; setItems(orderedItems); + return; } @@ -115,14 +116,15 @@ export const KanbanView = ({ itemsArray }: { itemsArray: any}) => { return; } - // reordering column - if (result.type === 'COLUMN') { - const reorderedItem = reorder(items, source.index, destination.index); + // TODO: fix issues with reordering column + // if (result.type === 'COLUMN') { + // const reorderedItem = reorder(items, source.index, destination.index); - setItems(reorderedItem); - - return; - } + // setItems(reorderedItem); + // // updateKanbanBoard(reorderedItem); + // // console.log('data '+ kanbandata) + // return; + // } const data = reorderItemMap({ itemMap: items, @@ -131,7 +133,7 @@ export const KanbanView = ({ itemsArray }: { itemsArray: any}) => { }); setItems(data.quoteItem); - + } const [enabled, setEnabled] = useState(false); From 42da0192cda72fe87db939e8fd3dbe2f58668621 Mon Sep 17 00:00:00 2001 From: desperado1802 Date: Mon, 11 Dec 2023 11:40:32 +0200 Subject: [PATCH 02/34] added device theme detect and set app's theme according to that in first app open --- apps/mobile/app/app.tsx | 74 ++++++++++----------- apps/mobile/app/navigators/AppNavigator.tsx | 25 ++++++- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/apps/mobile/app/app.tsx b/apps/mobile/app/app.tsx index 8b706947b..4f79ec1dc 100644 --- a/apps/mobile/app/app.tsx +++ b/apps/mobile/app/app.tsx @@ -9,24 +9,24 @@ * The app navigation resides in ./app/navigators, so head over there * if you're interested in adding screens and navigators. */ -import "./i18n" -import "./utils/ignoreWarnings" -import { useFonts } from "expo-font" -import React, { useEffect } from "react" -import { Provider as PaperProvider } from "react-native-paper" +import './i18n'; +import './utils/ignoreWarnings'; +import { useFonts } from 'expo-font'; +import React, { useEffect } from 'react'; +import { Provider as PaperProvider } from 'react-native-paper'; -import { initialWindowMetrics, SafeAreaProvider } from "react-native-safe-area-context" -import { useInitialRootStore, useStores } from "./models" -import { AppNavigator, useNavigationPersistence } from "./navigators" -import { ErrorBoundary } from "./screens/ErrorScreen/ErrorBoundary" -import * as storage from "./utils/storage" -import { customDarkTheme, customFontsToLoad, customLightTheme } from "./theme" -import { setupReactotron } from "./services/reactotron" -import Config from "./config" -import { observer } from "mobx-react-lite" -import { initCrashReporting } from "./utils/crashReporting" -import FlashMessage from "react-native-flash-message" -import { ClickOutsideProvider } from "react-native-click-outside" +import { initialWindowMetrics, SafeAreaProvider } from 'react-native-safe-area-context'; +import { useInitialRootStore, useStores } from './models'; +import { AppNavigator, useNavigationPersistence } from './navigators'; +import { ErrorBoundary } from './screens/ErrorScreen/ErrorBoundary'; +import * as storage from './utils/storage'; +import { customDarkTheme, customFontsToLoad, customLightTheme } from './theme'; +import { setupReactotron } from './services/reactotron'; +import Config from './config'; +import { observer } from 'mobx-react-lite'; +import { initCrashReporting } from './utils/crashReporting'; +import FlashMessage from 'react-native-flash-message'; +import { ClickOutsideProvider } from 'react-native-click-outside'; // Set up Reactotron, which is a free desktop app for inspecting and debugging // React Native apps. Learn more here: https://github.com/infinitered/reactotron @@ -34,40 +34,40 @@ setupReactotron({ // clear the Reactotron window when the app loads/reloads clearOnLoad: true, // generally going to be localhost - host: "localhost", + host: 'localhost', // Reactotron can monitor AsyncStorage for you useAsyncStorage: true, // log the initial restored state from AsyncStorage logInitialState: true, // log out any snapshots as they happen (this is useful for debugging but slow) - logSnapshots: false, -}) + logSnapshots: false +}); -export const NAVIGATION_PERSISTENCE_KEY = "NAVIGATION_STATE" +export const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE'; interface AppProps { - hideSplashScreen: () => Promise + hideSplashScreen: () => Promise; } /** * This is the root component of our app. */ const App = observer((props: AppProps) => { - const { hideSplashScreen } = props + const { hideSplashScreen } = props; const { initialNavigationState, onNavigationStateChange, - isRestored: isNavigationStateRestored, - } = useNavigationPersistence(storage, NAVIGATION_PERSISTENCE_KEY) + isRestored: isNavigationStateRestored + } = useNavigationPersistence(storage, NAVIGATION_PERSISTENCE_KEY); const { - authenticationStore: { isDarkMode }, - } = useStores() + authenticationStore: { isDarkMode } + } = useStores(); useEffect(() => { - initCrashReporting() // To initialize Sentry.io - }, []) + initCrashReporting(); // To initialize Sentry.io + }, []); - const [areFontsLoaded] = useFonts(customFontsToLoad) + const [areFontsLoaded] = useFonts(customFontsToLoad); const { rehydrated } = useInitialRootStore(() => { // This runs after the root store has been initialized and rehydrated. @@ -76,8 +76,8 @@ const App = observer((props: AppProps) => { // Slightly delaying splash screen hiding for better UX; can be customized or removed as needed, // Note: (vanilla Android) The splash-screen will not appear if you launch your app via the terminal or Android Studio. Kill the app and launch it normally by tapping on the launcher icon. https://stackoverflow.com/a/69831106 // Note: (vanilla iOS) You might notice the splash-screen logo change size. This happens in debug/development mode. Try building the app for release. - setTimeout(hideSplashScreen, 500) - }) + setTimeout(hideSplashScreen, 500); + }); // Before we show the app, we have to wait for our state to be ready. // In the meantime, don't render anything. This will be the background @@ -85,11 +85,11 @@ const App = observer((props: AppProps) => { // In iOS: application:didFinishLaunchingWithOptions: // In Android: https://stackoverflow.com/a/45838109/204044 // You can replace with your own loading component if you wish. - if (!rehydrated || !isNavigationStateRestored || !areFontsLoaded) return null + if (!rehydrated || !isNavigationStateRestored || !areFontsLoaded) return null; // otherwise, we're ready to render the app - const theme = isDarkMode ? customDarkTheme : customLightTheme + const theme = isDarkMode ? customDarkTheme : customLightTheme; return ( @@ -105,6 +105,6 @@ const App = observer((props: AppProps) => { - ) -}) -export default App + ); +}); +export default App; diff --git a/apps/mobile/app/navigators/AppNavigator.tsx b/apps/mobile/app/navigators/AppNavigator.tsx index 2979ded99..1ea89942d 100644 --- a/apps/mobile/app/navigators/AppNavigator.tsx +++ b/apps/mobile/app/navigators/AppNavigator.tsx @@ -11,7 +11,7 @@ import { import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { StackScreenProps } from '@react-navigation/stack'; import { observer } from 'mobx-react-lite'; -import React from 'react'; +import React, { useEffect } from 'react'; import Config from '../config'; import { QueryClient, QueryClientProvider } from 'react-query'; import { useStores } from '../models'; // @demo remove-current-line @@ -25,6 +25,8 @@ import { } from './AuthenticatedNavigator'; import { DemoTabParamList } from './DemoNavigator'; // @demo remove-current-line import { navigationRef, useBackButtonHandler } from './navigationUtilities'; +import { Appearance } from 'react-native'; +import AsyncStorage from '@react-native-async-storage/async-storage'; /** * This type allows TypeScript to know what routes are defined in this navigator @@ -94,6 +96,27 @@ const AppStack = observer(function AppStack() { interface NavigationProps extends Partial> {} export const AppNavigator = observer(function AppNavigator(props: NavigationProps) { + const { + authenticationStore: { isDarkMode, toggleTheme } + } = useStores(); + + useEffect(() => { + const checkAppInstallAndSetTheme = async () => { + const firstTimeAppOpen = await AsyncStorage.getItem('initialThemeSetupDone'); + + if (!firstTimeAppOpen) { + const colorsScheme = Appearance.getColorScheme(); + if (colorsScheme === 'dark' && !isDarkMode) { + toggleTheme(); + } else if (colorsScheme === 'light' && isDarkMode) { + toggleTheme(); + } + await AsyncStorage.setItem('initialThemeSetupDone', JSON.stringify(true)); + } + }; + checkAppInstallAndSetTheme(); + }, []); + useBackButtonHandler((routeName) => exitRoutes.includes(routeName)); const queryClient = new QueryClient(); return ( From db824370c111f4cd7a00e148fc2a16ec2db7449e Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 12:05:52 +0000 Subject: [PATCH 03/34] refactor: the RECAPTCHA keys are now fetched from the server --- apps/web/.env | 6 +- apps/web/app/constants.ts | 7 ++- apps/web/app/services/client/api/index.ts | 1 + apps/web/app/services/client/api/recaptcha.ts | 5 ++ .../web/lib/components/services/recaptcha.tsx | 13 +++-- apps/web/pages/api/auth/recaptcha.ts | 13 +++++ apps/web/pages/auth/team.tsx | 58 ++++++++++++------- 7 files changed, 72 insertions(+), 31 deletions(-) create mode 100644 apps/web/app/services/client/api/recaptcha.ts create mode 100644 apps/web/pages/api/auth/recaptcha.ts diff --git a/apps/web/.env b/apps/web/.env index 539845cf2..5728fb878 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -4,9 +4,9 @@ GAUZY_API_SERVER_URL=https://api.gauzy.co/api NEXT_PUBLIC_GAUZY_API_SERVER_URL=https://api.gauzy.co NEXT_PUBLIC_GA_MEASUREMENT_ID= -# CAPTCHA Settings -NEXT_PUBLIC_CAPTCHA_SITE_KEY= -CAPTCHA_SECRET_KEY= +# RECAPTCHA Settings +RECAPTCHA_SITE_KEY= +RECAPTCHA_SECRET_KEY= # Invite Callback URL INVITE_CALLBACK_URL=https://app.ever.team/auth/passcode diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 39ccdb801..ee727130f 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -28,8 +28,8 @@ export const NO_TEAM_POPUP_SHOW_COOKIE_NAME = 'no-team-popup-show'; export const ACTIVE_PROJECT_COOKIE_NAME = 'auth-active-project'; // Recaptcha -export const RECAPTCHA_SITE_KEY = process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY; -export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; +export const RECAPTCHA_SITE_KEY = process.env.RECAPTCHA_SITE_KEY; +export const RECAPTCHA_SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY; export const GAUZY_API_SERVER_URL = process.env.GAUZY_API_SERVER_URL || 'https://api.gauzy.co/api'; @@ -74,7 +74,8 @@ export const MEET_JWT_TOKEN_COOKIE_NAME = 'meet-jwt-session'; // BOARD board export const BOARD_APP_DOMAIN = process.env.NEXT_PUBLIC_BOARD_APP_DOMAIN || 'https://board.ever.team'; -export const BOARD_BACKEND_POST_URL = process.env.NEXT_PUBLIC_BOARD_BACKEND_POST_URL || 'https://jsonboard.ever.team/api/v2/post/'; +export const BOARD_BACKEND_POST_URL = + process.env.NEXT_PUBLIC_BOARD_BACKEND_POST_URL || 'https://jsonboard.ever.team/api/v2/post/'; export const BOARD_FIREBASE_CONFIG = process.env.NEXT_PUBLIC_BOARD_FIREBASE_CONFIG; // Jitsu diff --git a/apps/web/app/services/client/api/index.ts b/apps/web/app/services/client/api/index.ts index 24d25385a..e9e8ab2cb 100644 --- a/apps/web/app/services/client/api/index.ts +++ b/apps/web/app/services/client/api/index.ts @@ -29,3 +29,4 @@ export * from './integrations/types'; export * from './integrations'; export * from './organization-projects'; +export * from './recaptcha'; diff --git a/apps/web/app/services/client/api/recaptcha.ts b/apps/web/app/services/client/api/recaptcha.ts new file mode 100644 index 000000000..ad22ea973 --- /dev/null +++ b/apps/web/app/services/client/api/recaptcha.ts @@ -0,0 +1,5 @@ +import api from '../axios'; + +export const getRecaptchaAPI = () => { + return api.get('/auth/recaptcha'); +}; diff --git a/apps/web/lib/components/services/recaptcha.tsx b/apps/web/lib/components/services/recaptcha.tsx index 35e3235ed..68c07f6c2 100644 --- a/apps/web/lib/components/services/recaptcha.tsx +++ b/apps/web/lib/components/services/recaptcha.tsx @@ -1,22 +1,27 @@ -import { RECAPTCHA_SITE_KEY } from '@app/constants'; import ReCAPTCHA from 'react-google-recaptcha'; const ReactReCAPTCHA = ReCAPTCHA as any; export function SiteReCAPTCHA({ - key = RECAPTCHA_SITE_KEY, + siteKey, onChange, onErrored, onExpired, theme }: { - key?: string; + siteKey: string; onChange: (token: string | null) => void; onExpired?: () => void; onErrored?: () => void; theme?: string; }) { return ( - + ); } diff --git a/apps/web/pages/api/auth/recaptcha.ts b/apps/web/pages/api/auth/recaptcha.ts new file mode 100644 index 000000000..40e71429c --- /dev/null +++ b/apps/web/pages/api/auth/recaptcha.ts @@ -0,0 +1,13 @@ +import { RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY } from '@app/constants'; +import { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'GET') { + return res.status(405).json({ status: 'fail' }); + } + + res.status(200).json({ + RECAPTCHA_SITE_KEY: RECAPTCHA_SITE_KEY, + RECAPTCHA_SECRET_KEY: !!RECAPTCHA_SECRET_KEY // Must remain private + }); +} diff --git a/apps/web/pages/auth/team.tsx b/apps/web/pages/auth/team.tsx index 22f984cd5..5bc964abc 100644 --- a/apps/web/pages/auth/team.tsx +++ b/apps/web/pages/auth/team.tsx @@ -1,10 +1,10 @@ -import { RECAPTCHA_SITE_KEY } from '@app/constants'; import { useAuthenticationTeam, IStepProps } from '@app/hooks'; import { IClassName } from '@app/interfaces'; +import { getRecaptchaAPI } from '@app/services/client/api'; 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 { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; export default function AuthTeam() { @@ -122,7 +122,6 @@ function FillUserDataForm({ loading?: boolean; } & IClassName) { const { t } = useTranslation(); - const [feedback, setFeedback] = useState(''); return ( @@ -153,24 +152,7 @@ function FillUserDataForm({ onChange={handleOnChange} autoComplete="off" /> - { RECAPTCHA_SITE_KEY && -
-
- { - handleOnChange({ target: { name: 'recaptcha', value: res } }); - setFeedback(''); - }} - onErrored={() => setFeedback(t('errors.NETWORK_ISSUE'))} - /> - {(errors['recaptcha'] || feedback) && ( - - {errors['recaptcha'] || feedback} - - )} -
-
- } +
@@ -184,3 +166,37 @@ function FillUserDataForm({ ); } + +function ReCAPTCHA({ handleOnChange, errors }: { handleOnChange: any; errors: any }) { + const { t } = useTranslation(); + const [feedback, setFeedback] = useState(''); + + const [recaptchaKeys, setRecaptchaKeys] = useState<{ + RECAPTCHA_SITE_KEY: string; + RECAPTCHA_SECRET_KEY: boolean; + }>(); + + useEffect(() => { + getRecaptchaAPI().then(({ data }) => setRecaptchaKeys(data)); + }, []); + + const content = recaptchaKeys && recaptchaKeys.RECAPTCHA_SECRET_KEY && recaptchaKeys.RECAPTCHA_SITE_KEY && ( +
+
+ { + handleOnChange({ target: { name: 'recaptcha', value: res } }); + setFeedback(''); + }} + onErrored={() => setFeedback(t('errors.NETWORK_ISSUE'))} + /> + {(errors['recaptcha'] || feedback) && ( + {errors['recaptcha'] || feedback} + )} +
+
+ ); + + return content || <>; +} From 9ea24babe3142df95852a5f28aea0f5cf9b73b84 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 13:10:31 +0000 Subject: [PATCH 04/34] rename CAPTCHA variables --- apps/web/.env | 6 +++--- apps/web/app/constants.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/.env b/apps/web/.env index 5728fb878..539845cf2 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -4,9 +4,9 @@ GAUZY_API_SERVER_URL=https://api.gauzy.co/api NEXT_PUBLIC_GAUZY_API_SERVER_URL=https://api.gauzy.co NEXT_PUBLIC_GA_MEASUREMENT_ID= -# RECAPTCHA Settings -RECAPTCHA_SITE_KEY= -RECAPTCHA_SECRET_KEY= +# CAPTCHA Settings +NEXT_PUBLIC_CAPTCHA_SITE_KEY= +CAPTCHA_SECRET_KEY= # Invite Callback URL INVITE_CALLBACK_URL=https://app.ever.team/auth/passcode diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index ee727130f..368cf363b 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -28,8 +28,8 @@ export const NO_TEAM_POPUP_SHOW_COOKIE_NAME = 'no-team-popup-show'; export const ACTIVE_PROJECT_COOKIE_NAME = 'auth-active-project'; // Recaptcha -export const RECAPTCHA_SITE_KEY = process.env.RECAPTCHA_SITE_KEY; -export const RECAPTCHA_SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY; +export const RECAPTCHA_SITE_KEY = process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY; +export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; export const GAUZY_API_SERVER_URL = process.env.GAUZY_API_SERVER_URL || 'https://api.gauzy.co/api'; From a4d6ed774d2d5cda5794b6c16ffaa4c643691327 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:27:02 +0100 Subject: [PATCH 05/34] update:kanbanview props nomenclature --- apps/web/pages/kanban/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/pages/kanban/index.tsx b/apps/web/pages/kanban/index.tsx index 589389ca3..592075453 100644 --- a/apps/web/pages/kanban/index.tsx +++ b/apps/web/pages/kanban/index.tsx @@ -11,7 +11,7 @@ const Kanban= () => { <> {Object.keys(data).length > 0 ? - + : null } From ef56787800de691de0425a0be8aea46e64f44b18 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:27:35 +0100 Subject: [PATCH 06/34] chore:format code and update task on drag --- .../lib/features/team-members-kanban-view.tsx | 133 ++++++++++-------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/web/lib/features/team-members-kanban-view.tsx b/apps/web/lib/features/team-members-kanban-view.tsx index 6a166e576..7e871034e 100644 --- a/apps/web/lib/features/team-members-kanban-view.tsx +++ b/apps/web/lib/features/team-members-kanban-view.tsx @@ -8,67 +8,78 @@ import React from "react"; import { useEffect, useState } from "react"; import { DragDropContext, DraggableLocation, DropResult, Droppable, DroppableProvided, DroppableStateSnapshot } from "react-beautiful-dnd"; -const reorder = (list: ITeamTask[], startIndex:number , endIndex:number ) => { - const result = Array.from(list); - const [removed] = result.splice(startIndex, 1); - result.splice(endIndex, 0, removed); - - return result; -}; -const reorderItemMap = ({ itemMap, source, destination }: { - itemMap: IKanban, - source: DraggableLocation, - destination: DraggableLocation -}) => { - const current = [...itemMap[source.droppableId]]; - const next = [...itemMap[destination.droppableId]]; - const target = current[source.index]; +export const KanbanView = ({ kanbanBoardTasks }: { kanbanBoardTasks: IKanban}) => { - // moving to same list - if (source.droppableId === destination.droppableId) { - const reordered = reorder(current, source.index, destination.index); - const result = { - ...itemMap, - [source.droppableId]: reordered, + const { columns:kanbanColumns, updateKanbanBoard, updateTaskStatus } = useKanban(); + + const [items, setItems] = useState(kanbanBoardTasks); + + const [columns, setColumn] = useState(Object.keys(kanbanBoardTasks)); + + const reorderTask = (list: ITeamTask[], startIndex:number , endIndex:number ) => { + const tasks = Array.from(list); + const [removedTask] = tasks.splice(startIndex, 1); + tasks.splice(endIndex, 0, removedTask); + + return tasks; }; - return { - quoteItem: result, + + const reorderKanbanTasks = ({ kanbanTasks, source, destination }: { + kanbanTasks: IKanban, + source: DraggableLocation, + destination: DraggableLocation + }) => { + const sourceDroppableID = source.droppableId; + const destinationDroppableID = destination.droppableId; + const sourceIndex = source.index; + const destinationIndex = destination.index; + const currentTaskStatus = [...kanbanTasks[sourceDroppableID]]; + const nextTaskStatus = [...kanbanTasks[destinationDroppableID]]; + const targetStatus = currentTaskStatus[source.index]; + + // moving to same list + if (sourceDroppableID === destinationDroppableID) { + const reorderedKanbanTasks = reorderTask(currentTaskStatus, sourceIndex, destinationIndex); + const result = { + ...kanbanTasks, + [sourceDroppableID]: reorderedKanbanTasks, + }; + return { + kanbanBoard: result, + }; + } + + // remove from original + currentTaskStatus.splice(sourceIndex, 1); + + const updateTaskStatusData = {...targetStatus, status: destinationDroppableID}; + + // update task status on server + updateTaskStatus(updateTaskStatusData); + + // insert into next + nextTaskStatus.splice(destinationIndex, 0, updateTaskStatusData); + + const result = { + ...kanbanTasks, + [sourceDroppableID]: currentTaskStatus, + [destinationDroppableID]: nextTaskStatus, + }; + + return { + kanbanBoard: result, + }; }; - } - - // remove from original - current.splice(source.index, 1); - // insert into next - next.splice(destination.index, 0, target); - - const result = { - ...itemMap, - [source.droppableId]: current, - [destination.droppableId]: next, - }; - - return { - quoteItem: result, - }; -}; - -const getHeaderBackground = (columns: ITaskStatusItemList[], column: string) => { - - const selectState = columns.filter((item: ITaskStatusItemList)=> { - return item.name === column - }); - - return selectState[0].color -} - -export const KanbanView = ({ itemsArray }: { itemsArray: IKanban}) => { - - const { columns:kanbanColumns, updateKanbanBoard, data:kanbandata } = useKanban(); - - const [items, setItems] = useState(itemsArray); - - const [columns, setColumn] = useState(Object.keys(itemsArray)); + + const getHeaderBackground = (columns: ITaskStatusItemList[], column: string) => { + + const selectState = columns.filter((item: ITaskStatusItemList)=> { + return item.name === column + }); + + return selectState[0].color + } /** * This function handles all drag and drop logic @@ -126,14 +137,14 @@ export const KanbanView = ({ itemsArray }: { itemsArray: IKanban}) => { // return; // } - const data = reorderItemMap({ - itemMap: items, + const data = reorderKanbanTasks({ + kanbanTasks: items, source, destination, }); - setItems(data.quoteItem); - + setItems(data.kanbanBoard); + updateKanbanBoard(() => data.kanbanBoard) } const [enabled, setEnabled] = useState(false); From c3b6f1b033beeaa587e9a027eac78bf8cfba3a21 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:29:23 +0100 Subject: [PATCH 07/34] update: add discriminated union to itaskstatus --- apps/web/app/interfaces/ITask.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/interfaces/ITask.ts b/apps/web/app/interfaces/ITask.ts index 6f28b51f0..41ece5e9c 100644 --- a/apps/web/app/interfaces/ITask.ts +++ b/apps/web/app/interfaces/ITask.ts @@ -132,7 +132,7 @@ export type ITaskStatusField = | 'tags'; export type ITaskStatusStack = { - status: ITaskStatus; + status: ITaskStatus | string; size: ITaskSize; label: ITaskLabel; priority: ITaskPriority; From fbb2d91a32618a817e700954f96a6927a356ccdd Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:30:04 +0100 Subject: [PATCH 08/34] update:add new return values to usekanban --- apps/web/app/hooks/features/useKanban.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/web/app/hooks/features/useKanban.ts b/apps/web/app/hooks/features/useKanban.ts index dac4f75d8..0c0bc2659 100644 --- a/apps/web/app/hooks/features/useKanban.ts +++ b/apps/web/app/hooks/features/useKanban.ts @@ -12,9 +12,9 @@ export function useKanban() { const [kanbanBoard, setKanbanBoard] = useRecoilState(kanbanBoardState); const taskStatusHook = useTaskStatus(); - const { tasks, tasksFetching } = useTeamTasks(); - + const { tasks, tasksFetching, updateTask } = useTeamTasks(); + /** * format data for kanban board */ @@ -42,6 +42,8 @@ export function useKanban() { return { data: kanbanBoard, isLoading: loading, - columns: taskStatusHook.taskStatus + columns: taskStatusHook.taskStatus, + updateKanbanBoard: setKanbanBoard, + updateTaskStatus: updateTask } } \ No newline at end of file From 84f4409a8482edf1998462fc44bd7b648329a4e3 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:43:57 +0100 Subject: [PATCH 09/34] feat:add taskstatus to constants --- apps/web/app/constants.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 39ccdb801..ee096833a 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -125,3 +125,7 @@ export enum IssuesView { TABLE = 'TABLE', BLOCKS = 'BLOCKS' } + +export const TaskStatus = { + INPROGRESS: 'in-progress' +} From df8bb24f39dd85f75b7b051ba53ddaf7c2e7dc6d Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:44:25 +0100 Subject: [PATCH 10/34] update:chnage inprogressbar condition --- apps/web/lib/components/Kanban.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/lib/components/Kanban.tsx b/apps/web/lib/components/Kanban.tsx index b615790f0..fd8ef7f88 100644 --- a/apps/web/lib/components/Kanban.tsx +++ b/apps/web/lib/components/Kanban.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react'; import { Draggable, DraggableProvided, DraggableStateSnapshot, Droppable, DroppableProvided, DroppableStateSnapshot } from 'react-beautiful-dnd'; import Item from './kanban-card'; import { ITeamTask } from '@app/interfaces'; +import { TaskStatus } from '@app/constants'; const grid = 8; @@ -63,7 +64,7 @@ function InnerItemList({items, title}: { isDragging={dragSnapshot.isDragging} isGroupedOver={Boolean(dragSnapshot.combineTargetFor)} provided={dragProvided} - style={title === 'review' && { + style={title === TaskStatus.INPROGRESS && { borderWidth: '1px', borderColor: '#6FCF97', borderStyle: 'solid' From 23df3147ff305c0299e195027a00c513a3fbfc10 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:52:45 +0100 Subject: [PATCH 11/34] update:display task tags --- apps/web/lib/components/kanban-card.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/web/lib/components/kanban-card.tsx b/apps/web/lib/components/kanban-card.tsx index 2a7d5e9be..a0ae1284f 100644 --- a/apps/web/lib/components/kanban-card.tsx +++ b/apps/web/lib/components/kanban-card.tsx @@ -4,6 +4,7 @@ import VerticalThreeDot from "@components/ui/svgs/vertical-three-dot"; import { DraggableProvided } from "react-beautiful-dnd"; import CircularProgress from "@components/ui/svgs/circular-progress"; import PriorityIcon from "@components/ui/svgs/priority-icon"; +import { Tag } from "@app/interfaces"; function getStyle(provided: DraggableProvided, style: any) { if (!style) { @@ -37,7 +38,7 @@ function setCommentIconColor(commentType: "tagged" | "untagged") { return style } -function Tag({title, backgroundColor, color}: { +function TagCard({title, backgroundColor, color}: { title: string, backgroundColor: string, color: string @@ -64,17 +65,17 @@ function Tag({title, backgroundColor, color}: { } function TagList({tags}: { - tags: any[] + tags: Tag[] }){ return ( <>
- {tags.map((tag: any, index: number)=> { + {tags.map((tag: Tag, index: number)=> { return ( - ) From fe79a17c48ad500b27f4d53de070752e785c5219 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 22:56:55 +0100 Subject: [PATCH 12/34] chore: change comment condition --- apps/web/lib/components/kanban-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/lib/components/kanban-card.tsx b/apps/web/lib/components/kanban-card.tsx index a0ae1284f..909a7efd9 100644 --- a/apps/web/lib/components/kanban-card.tsx +++ b/apps/web/lib/components/kanban-card.tsx @@ -195,7 +195,7 @@ export default function Item(props: any) {
- {item.hasComment !== "none" && + {item.hasComment && (
Date: Mon, 11 Dec 2023 23:01:33 +0100 Subject: [PATCH 13/34] chore:change any to right interface --- apps/web/lib/components/Kanban.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/lib/components/Kanban.tsx b/apps/web/lib/components/Kanban.tsx index fd8ef7f88..1f6cdb8af 100644 --- a/apps/web/lib/components/Kanban.tsx +++ b/apps/web/lib/components/Kanban.tsx @@ -169,7 +169,7 @@ export const KanbanDroppable = ({ title, droppableId, type, content }: { export const EmptyKanbanDroppable = ({index,title, items}: { index: number; title: string; - items: any; + items: ITeamTask[]; })=> { const [enabled, setEnabled] = useState(false); From b4982c32b06ad399ca977b4978a12199b2e40509 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 23:14:45 +0100 Subject: [PATCH 14/34] chore:remove unnecessary discrimant --- apps/web/app/interfaces/ITask.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/interfaces/ITask.ts b/apps/web/app/interfaces/ITask.ts index 41ece5e9c..6f28b51f0 100644 --- a/apps/web/app/interfaces/ITask.ts +++ b/apps/web/app/interfaces/ITask.ts @@ -132,7 +132,7 @@ export type ITaskStatusField = | 'tags'; export type ITaskStatusStack = { - status: ITaskStatus | string; + status: ITaskStatus; size: ITaskSize; label: ITaskLabel; priority: ITaskPriority; From e2ad071b914b96e990859b562315c570531dfb4a Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 23:15:12 +0100 Subject: [PATCH 15/34] fix:resolve issues with destinationDroppableid --- apps/web/lib/features/team-members-kanban-view.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/lib/features/team-members-kanban-view.tsx b/apps/web/lib/features/team-members-kanban-view.tsx index 7e871034e..bb1a03ee8 100644 --- a/apps/web/lib/features/team-members-kanban-view.tsx +++ b/apps/web/lib/features/team-members-kanban-view.tsx @@ -1,5 +1,5 @@ import { useKanban } from "@app/hooks/features/useKanban"; -import { ITaskStatusItemList, ITeamTask } from "@app/interfaces"; +import { ITaskStatus, ITaskStatusItemList, ITeamTask } from "@app/interfaces"; import { IKanban } from "@app/interfaces/IKanban"; import { clsxm } from "@app/utils"; import KanbanDraggable, { EmptyKanbanDroppable } from "lib/components/Kanban" @@ -52,8 +52,10 @@ export const KanbanView = ({ kanbanBoardTasks }: { kanbanBoardTasks: IKanban}) = // remove from original currentTaskStatus.splice(sourceIndex, 1); + + const taskstatus = destinationDroppableID as ITaskStatus; - const updateTaskStatusData = {...targetStatus, status: destinationDroppableID}; + const updateTaskStatusData = {...targetStatus, status: taskstatus}; // update task status on server updateTaskStatus(updateTaskStatusData); From 6ff81274e5c51996709547dadc9cb7e823519b60 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Mon, 11 Dec 2023 23:21:40 +0100 Subject: [PATCH 16/34] update:add new words to cspell --- .cspell.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cspell.json b/.cspell.json index e3d1426b9..31a99cd2f 100644 --- a/.cspell.json +++ b/.cspell.json @@ -52,6 +52,7 @@ "ipsum", "JITSU", "kanban", + "kanbandata", "Lorem", "libappindicator", "lucide", @@ -73,6 +74,7 @@ "testid", "Timesheet", "tanstack", + "taskstatus", "tempor", "vcpu", "Vercel", From 6464926c8ec2cd204454bfbfcb9a540b99583033 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:14:19 +0000 Subject: [PATCH 17/34] chore: load public envs variable from server props --- apps/web/app/constants.ts | 15 +++-- apps/web/app/env.ts | 57 +++++++++++++++++++ apps/web/app/helpers/cookies/helpers.ts | 4 +- apps/web/components/ui/services/recaptcha.tsx | 7 +-- apps/web/lib/app/init-state.tsx | 2 +- apps/web/pages/_app.tsx | 16 ++++-- apps/web/pages/auth/team.tsx | 17 ++---- 7 files changed, 88 insertions(+), 30 deletions(-) create mode 100644 apps/web/app/env.ts diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 368cf363b..108569c50 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -1,5 +1,6 @@ import { JitsuOptions } from '@jitsu/jitsu-react/dist/useJitsu'; import { I_SMTPRequest } from './interfaces/ISmtp'; +import { getNextPublicEnv } from './env'; export const API_BASE_URL = '/api'; export const DEFAULT_APP_PATH = '/auth/passcode'; @@ -28,7 +29,7 @@ export const NO_TEAM_POPUP_SHOW_COOKIE_NAME = 'no-team-popup-show'; export const ACTIVE_PROJECT_COOKIE_NAME = 'auth-active-project'; // Recaptcha -export const RECAPTCHA_SITE_KEY = process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY; +export const RECAPTCHA_SITE_KEY = getNextPublicEnv('NEXT_PUBLIC_CAPTCHA_SITE_KEY'); export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; export const GAUZY_API_SERVER_URL = process.env.GAUZY_API_SERVER_URL || 'https://api.gauzy.co/api'; @@ -37,7 +38,7 @@ export const INVITE_CALLBACK_URL = process.env.INVITE_CALLBACK_URL || 'https://a export const INVITE_CALLBACK_PATH = '/auth/passcode'; export const VERIFY_EMAIL_CALLBACK_URL = process.env.VERIFY_EMAIL_CALLBACK_URL || 'https://app.ever.team/verify-email'; export const VERIFY_EMAIL_CALLBACK_PATH = '/verify-email'; -export const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID; +export const GA_MEASUREMENT_ID = getNextPublicEnv('NEXT_PUBLIC_GA_MEASUREMENT_ID'); export const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS || 'noreply@ever.team'; export const SMTP_HOST = process.env.SMTP_HOST || ''; @@ -45,7 +46,7 @@ export const SMTP_PORT = process.env.SMTP_PORT || ''; export const SMTP_SECURE = process.env.SMTP_SECURE || ''; export const SMTP_USERNAME = process.env.SMTP_USERNAME || ''; export const SMTP_PASSWORD = process.env.SMTP_PASSWORD || ''; -export const DISABLE_AUTO_REFRESH = process.env.NEXT_PUBLIC_DISABLE_AUTO_REFRESH === 'true'; +export const DISABLE_AUTO_REFRESH = getNextPublicEnv('NEXT_PUBLIC_DISABLE_AUTO_REFRESH'); export const APP_NAME = process.env.APP_NAME || 'Ever Teams'; export const APP_SIGNATURE = process.env.APP_SIGNATURE || 'Ever Teams'; @@ -64,7 +65,13 @@ export const smtpConfiguration: () => I_SMTPRequest = () => ({ }); // Cookies -export const COOKIE_DOMAINS = (process.env.NEXT_PUBLIC_COOKIE_DOMAINS || 'ever.team').split(',').map((d) => d.trim()); +// export const COOKIE_DOMAINS = (process.env.NEXT_PUBLIC_COOKIE_DOMAINS || 'ever.team').split(',').map((d) => d.trim()); +export const COOKIE_DOMAINS = getNextPublicEnv('NEXT_PUBLIC_COOKIE_DOMAINS', { + default: 'ever.team', + map(value) { + return value?.split(',').map((d) => d.trim()) || []; + } +}); // MEET Constants export const MEET_DOMAIN = process.env.NEXT_PUBLIC_MEET_DOMAIN || 'meet.ever.team'; diff --git a/apps/web/app/env.ts b/apps/web/app/env.ts new file mode 100644 index 000000000..2019c6c63 --- /dev/null +++ b/apps/web/app/env.ts @@ -0,0 +1,57 @@ +const NEXT_PUBLIC_ENVS: { value: Env } = { value: {} }; + +type Env = Record; + +type Options = + | string + | { + default?: string; + map?: (value: string | undefined) => T; + }; + +type InferValue = T extends { map: (value: any) => infer U } ? U : string | undefined; + +type ReturnedType = { + readonly value: T extends string ? string : InferValue; +}; + +export function getNextPublicEnv>(name: string, options?: O): ReturnedType { + return { + get value() { + let value = typeof options === 'string' ? options : options?.default; + value = NEXT_PUBLIC_ENVS.value[name] || value; + + if (typeof options === 'object' && options.map) { + value = options.map(value) as any; + } + + return value as any; + } + }; +} + +export function setNextPublicEnv(envs: Env) { + if (envs) { + NEXT_PUBLIC_ENVS.value = { + ...NEXT_PUBLIC_ENVS.value, + ...envs + }; + } +} + +export function loadNextPublicEnvs() { + return Object.keys(process.env) + .filter((key) => key.startsWith('NEXT_PUBLIC')) + .reduce( + (acc, value) => { + if (process.env[value]) { + acc[value] = process.env[value] as string; + } + return acc; + }, + {} as Record + ); +} + +// Preload Some variables +setNextPublicEnv(loadNextPublicEnvs()); diff --git a/apps/web/app/helpers/cookies/helpers.ts b/apps/web/app/helpers/cookies/helpers.ts index 9c0e0782a..980e1024d 100644 --- a/apps/web/app/helpers/cookies/helpers.ts +++ b/apps/web/app/helpers/cookies/helpers.ts @@ -4,7 +4,7 @@ import { deleteCookie as _deleteCookie, getCookie as _getCookie, setCookie as _s export const deleteCookie: typeof _deleteCookie = (key, options) => { _deleteCookie(key, options); - COOKIE_DOMAINS.forEach((domain) => { + COOKIE_DOMAINS.value.forEach((domain) => { _deleteCookie(key, { domain, ...options @@ -22,7 +22,7 @@ export const setCookie: SetCookie = (key, data, options, crossSite) => { _setCookie(key, data, options); crossSite && - COOKIE_DOMAINS.forEach((domain) => { + COOKIE_DOMAINS.value.forEach((domain) => { _setCookie(key, data, { domain, ...options diff --git a/apps/web/components/ui/services/recaptcha.tsx b/apps/web/components/ui/services/recaptcha.tsx index f3606d44e..41b930157 100644 --- a/apps/web/components/ui/services/recaptcha.tsx +++ b/apps/web/components/ui/services/recaptcha.tsx @@ -1,18 +1,17 @@ -import { RECAPTCHA_SITE_KEY } from '@app/constants'; import ReCAPTCHA from 'react-google-recaptcha'; const ReactReCAPTCHA = ReCAPTCHA as any; export function SiteReCAPTCHA({ - key = RECAPTCHA_SITE_KEY, + siteKey, onChange, onErrored, onExpired }: { - key?: string; + siteKey: string; onChange: (token: string | null) => void; onExpired?: () => void; onErrored?: () => void; }) { - return ; + return ; } diff --git a/apps/web/lib/app/init-state.tsx b/apps/web/lib/app/init-state.tsx index 2fd2bd7b5..a0f96ce87 100644 --- a/apps/web/lib/app/init-state.tsx +++ b/apps/web/lib/app/init-state.tsx @@ -121,7 +121,7 @@ function InitState() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - return DISABLE_AUTO_REFRESH !== true ? : <>; + return DISABLE_AUTO_REFRESH.value !== 'true' ? : <>; } function useOneTimeLoad(func: () => void) { diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index 845ca8655..1da5b1355 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -1,4 +1,5 @@ /* eslint-disable no-mixed-spaces-and-tabs */ +import { loadNextPublicEnvs, setNextPublicEnv } from '@app/env'; import { GA_MEASUREMENT_ID, jitsuConfiguration } from '@app/constants'; import { JitsuProvider } from '@jitsu/jitsu-react'; import { Analytics } from '@vercel/analytics/react'; @@ -11,33 +12,35 @@ import Head from 'next/head'; import Script from 'next/script'; import { I18nextProvider } from 'react-i18next'; import { SkeletonTheme } from 'react-loading-skeleton'; -import 'react-loading-skeleton/dist/skeleton.css'; import { RecoilRoot } from 'recoil'; import { JitsuAnalytics } from '../lib/components/services/jitsu-analytics'; import i18n from '../ni18n.config'; +import 'react-loading-skeleton/dist/skeleton.css'; import '../styles/globals.css'; const MyApp = ({ Component, pageProps }: AppProps) => { const jitsuConf = pageProps?.jitsuConf; - console.log('Jitsu Host', pageProps); console.log(`Jitsu Configuration: ${JSON.stringify(jitsuConf)}`); const isJitsuEnvsPresent: boolean = jitsuConf?.host !== '' && jitsuConf?.writeKey !== ''; console.log(`Jitsu Enabled: ${isJitsuEnvsPresent}`); + // Set Envs to availabe on client side + setNextPublicEnv(pageProps.envs); + return ( <> - {GA_MEASUREMENT_ID && ( + {GA_MEASUREMENT_ID.value && ( <> )} @@ -105,7 +108,8 @@ MyApp.getInitialProps = async ({ Component, ctx }: { Component: NextPage(''); - const [recaptchaKeys, setRecaptchaKeys] = useState<{ - RECAPTCHA_SITE_KEY: string; - RECAPTCHA_SECRET_KEY: boolean; - }>(); - - useEffect(() => { - getRecaptchaAPI().then(({ data }) => setRecaptchaKeys(data)); - }, []); - - const content = recaptchaKeys && recaptchaKeys.RECAPTCHA_SECRET_KEY && recaptchaKeys.RECAPTCHA_SITE_KEY && ( + const content = RECAPTCHA_SITE_KEY.value && (
{ handleOnChange({ target: { name: 'recaptcha', value: res } }); setFeedback(''); From 45796d49d75831109c55f5c02c3bfb34ee58f4f7 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:17:00 +0000 Subject: [PATCH 18/34] fixed build errors --- apps/web/app/env.ts | 11 +++++------ apps/web/pages/_app.tsx | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/web/app/env.ts b/apps/web/app/env.ts index 2019c6c63..d9a236b41 100644 --- a/apps/web/app/env.ts +++ b/apps/web/app/env.ts @@ -2,12 +2,11 @@ const NEXT_PUBLIC_ENVS: { value: Env } = { value: {} }; type Env = Record; -type Options = - | string - | { - default?: string; - map?: (value: string | undefined) => T; - }; +type Poptions = { + default?: string; + map?: (value: string | undefined) => T; +}; +type Options = string | Poptions; type InferValue = T extends { map: (value: any) => infer U } ? U : string | undefined; diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index 1da5b1355..1e5d661c8 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -19,15 +19,15 @@ import 'react-loading-skeleton/dist/skeleton.css'; import '../styles/globals.css'; const MyApp = ({ Component, pageProps }: AppProps) => { + // Set Envs to availabe on client side + setNextPublicEnv(pageProps.envs); + const jitsuConf = pageProps?.jitsuConf; console.log(`Jitsu Configuration: ${JSON.stringify(jitsuConf)}`); const isJitsuEnvsPresent: boolean = jitsuConf?.host !== '' && jitsuConf?.writeKey !== ''; console.log(`Jitsu Enabled: ${isJitsuEnvsPresent}`); - // Set Envs to availabe on client side - setNextPublicEnv(pageProps.envs); - return ( <> {GA_MEASUREMENT_ID.value && ( From 331cc3ef6eabc0fd91f1bee3ccbf9183a78c7432 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:19:23 +0000 Subject: [PATCH 19/34] Remove outdated reCAPTCHA API code --- apps/web/app/services/client/api/recaptcha.ts | 5 ----- apps/web/pages/api/auth/recaptcha.ts | 13 ------------- 2 files changed, 18 deletions(-) delete mode 100644 apps/web/app/services/client/api/recaptcha.ts delete mode 100644 apps/web/pages/api/auth/recaptcha.ts diff --git a/apps/web/app/services/client/api/recaptcha.ts b/apps/web/app/services/client/api/recaptcha.ts deleted file mode 100644 index ad22ea973..000000000 --- a/apps/web/app/services/client/api/recaptcha.ts +++ /dev/null @@ -1,5 +0,0 @@ -import api from '../axios'; - -export const getRecaptchaAPI = () => { - return api.get('/auth/recaptcha'); -}; diff --git a/apps/web/pages/api/auth/recaptcha.ts b/apps/web/pages/api/auth/recaptcha.ts deleted file mode 100644 index 40e71429c..000000000 --- a/apps/web/pages/api/auth/recaptcha.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY } from '@app/constants'; -import { NextApiRequest, NextApiResponse } from 'next'; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'GET') { - return res.status(405).json({ status: 'fail' }); - } - - res.status(200).json({ - RECAPTCHA_SITE_KEY: RECAPTCHA_SITE_KEY, - RECAPTCHA_SECRET_KEY: !!RECAPTCHA_SECRET_KEY // Must remain private - }); -} From 4dce25f4222a652ec06f40ba66a2d4b66792fd7a Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:21:58 +0000 Subject: [PATCH 20/34] feat: Update MEET_DOMAIN constant and its usage --- apps/web/app/constants.ts | 2 +- apps/web/lib/features/integrations/meet/index.tsx | 2 +- apps/web/pages/api/auth/meet/jwt.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 108569c50..11ba8afca 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -74,7 +74,7 @@ export const COOKIE_DOMAINS = getNextPublicEnv('NEXT_PUBLIC_COOKIE_DOMAINS', { }); // MEET Constants -export const MEET_DOMAIN = process.env.NEXT_PUBLIC_MEET_DOMAIN || 'meet.ever.team'; +export const MEET_DOMAIN = getNextPublicEnv('NEXT_PUBLIC_MEET_DOMAIN', 'meet.ever.team'); export const MEET_JWT_APP_ID = process.env.MEET_JWT_APP_ID || 'ever_teams'; export const MEET_JWT_APP_SECRET = process.env.MEET_JWT_APP_SECRET; export const MEET_JWT_TOKEN_COOKIE_NAME = 'meet-jwt-session'; diff --git a/apps/web/lib/features/integrations/meet/index.tsx b/apps/web/lib/features/integrations/meet/index.tsx index c909ac17f..6a8c4602b 100644 --- a/apps/web/lib/features/integrations/meet/index.tsx +++ b/apps/web/lib/features/integrations/meet/index.tsx @@ -7,7 +7,7 @@ export default function MeetPage({ jwt, roomName }: { jwt: string; roomName: str return ( Date: Mon, 11 Dec 2023 23:23:12 +0000 Subject: [PATCH 21/34] fixed build errors --- apps/web/app/services/client/api/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/app/services/client/api/index.ts b/apps/web/app/services/client/api/index.ts index e9e8ab2cb..24d25385a 100644 --- a/apps/web/app/services/client/api/index.ts +++ b/apps/web/app/services/client/api/index.ts @@ -29,4 +29,3 @@ export * from './integrations/types'; export * from './integrations'; export * from './organization-projects'; -export * from './recaptcha'; From 367bd396b3709cc97e13f8af5835382de9a5d5b6 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:29:13 +0000 Subject: [PATCH 22/34] feat: Update board constants and Firebase configuration --- apps/web/app/constants.ts | 10 ++++++---- apps/web/app/hooks/useCollaborative.ts | 4 ++-- .../features/integrations/boards/export-to-backend.ts | 6 +++--- apps/web/lib/features/integrations/boards/firebase.ts | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 11ba8afca..7d463a64b 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -80,10 +80,12 @@ export const MEET_JWT_APP_SECRET = process.env.MEET_JWT_APP_SECRET; export const MEET_JWT_TOKEN_COOKIE_NAME = 'meet-jwt-session'; // BOARD board -export const BOARD_APP_DOMAIN = process.env.NEXT_PUBLIC_BOARD_APP_DOMAIN || 'https://board.ever.team'; -export const BOARD_BACKEND_POST_URL = - process.env.NEXT_PUBLIC_BOARD_BACKEND_POST_URL || 'https://jsonboard.ever.team/api/v2/post/'; -export const BOARD_FIREBASE_CONFIG = process.env.NEXT_PUBLIC_BOARD_FIREBASE_CONFIG; +export const BOARD_APP_DOMAIN = getNextPublicEnv('NEXT_PUBLIC_BOARD_APP_DOMAIN', 'https://board.ever.team'); +export const BOARD_BACKEND_POST_URL = getNextPublicEnv( + 'NEXT_PUBLIC_BOARD_BACKEND_POST_URL', + 'https://jsonboard.ever.team/api/v2/post/' +); +export const BOARD_FIREBASE_CONFIG = getNextPublicEnv('NEXT_PUBLIC_BOARD_FIREBASE_CONFIG'); // Jitsu export const jitsuConfiguration: () => JitsuOptions = () => ({ diff --git a/apps/web/app/hooks/useCollaborative.ts b/apps/web/app/hooks/useCollaborative.ts index 24b552486..b285330cf 100644 --- a/apps/web/app/hooks/useCollaborative.ts +++ b/apps/web/app/hooks/useCollaborative.ts @@ -65,8 +65,8 @@ export function useCollaborative(user?: IUser) { const onBoardClick = useCallback(() => { const members = collaborativeMembers.map((m) => m.id).join(','); - if (collaborativeMembers.length > 0 && BOARD_APP_DOMAIN) { - const url = new URL(BOARD_APP_DOMAIN); + if (collaborativeMembers.length > 0 && BOARD_APP_DOMAIN.value) { + const url = new URL(BOARD_APP_DOMAIN.value); url.searchParams.set('live', 'true'); url.searchParams.set('members', btoa(members)); diff --git a/apps/web/lib/features/integrations/boards/export-to-backend.ts b/apps/web/lib/features/integrations/boards/export-to-backend.ts index 870d5ea5a..d708873f1 100644 --- a/apps/web/lib/features/integrations/boards/export-to-backend.ts +++ b/apps/web/lib/features/integrations/boards/export-to-backend.ts @@ -15,7 +15,7 @@ export const exportToBackend = async ( appState: Partial, files: BinaryFiles ): Promise => { - if (!BOARD_BACKEND_POST_URL || !BOARD_APP_DOMAIN) { + if (!BOARD_BACKEND_POST_URL.value || !BOARD_APP_DOMAIN.value) { return { url: null, errorMessage: 'could Not Create Shareable Link' }; } @@ -40,13 +40,13 @@ export const exportToBackend = async ( maxBytes: FILE_UPLOAD_MAX_BYTES }); - const response = await fetch(BOARD_BACKEND_POST_URL, { + const response = await fetch(BOARD_BACKEND_POST_URL.value, { method: 'POST', body: payload.buffer }); const json = await response.json(); if (json.id) { - const url = new URL(BOARD_APP_DOMAIN); + const url = new URL(BOARD_APP_DOMAIN.value); // We need to store the key (and less importantly the id) as hash instead // of queryParam in order to never send it to the server url.hash = `json=${json.id},${encryptionKey}`; diff --git a/apps/web/lib/features/integrations/boards/firebase.ts b/apps/web/lib/features/integrations/boards/firebase.ts index a807b444d..20b4c4b9c 100644 --- a/apps/web/lib/features/integrations/boards/firebase.ts +++ b/apps/web/lib/features/integrations/boards/firebase.ts @@ -14,10 +14,10 @@ const _loadFirebase = async () => { if (!isFirebaseInitialized) { try { - if (!BOARD_FIREBASE_CONFIG) { + if (!BOARD_FIREBASE_CONFIG.value) { throw Error('Invalid Firebase configuration'); } - firebase.initializeApp(JSON.parse(BOARD_FIREBASE_CONFIG)); + firebase.initializeApp(JSON.parse(BOARD_FIREBASE_CONFIG.value)); } catch (error: any) { // trying initialize again throws. Usually this is harmless, and happens // mainly in dev (HMR) From ca5aa6b90b48d92d1f4f28dd06c8225a293db8e8 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:33:18 +0000 Subject: [PATCH 23/34] feat: Improve retrieval of GitHub app name configuration --- apps/web/app/constants.ts | 3 +-- apps/web/lib/settings/integration-setting.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 7d463a64b..edb86fd19 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -65,7 +65,6 @@ export const smtpConfiguration: () => I_SMTPRequest = () => ({ }); // Cookies -// export const COOKIE_DOMAINS = (process.env.NEXT_PUBLIC_COOKIE_DOMAINS || 'ever.team').split(',').map((d) => d.trim()); export const COOKIE_DOMAINS = getNextPublicEnv('NEXT_PUBLIC_COOKIE_DOMAINS', { default: 'ever.team', map(value) { @@ -98,7 +97,7 @@ export const jitsuConfiguration: () => JitsuOptions = () => ({ }); // Github Integration -export const GITHUB_APP_NAME = process.env.NEXT_PUBLIC_GITHUB_APP_NAME || 'ever-github'; +export const GITHUB_APP_NAME = getNextPublicEnv('NEXT_PUBLIC_GITHUB_APP_NAME', 'ever-github'); // Application Languages export const APPLICATION_LANGUAGES = [ diff --git a/apps/web/lib/settings/integration-setting.tsx b/apps/web/lib/settings/integration-setting.tsx index 03c3e990d..ea72f157b 100644 --- a/apps/web/lib/settings/integration-setting.tsx +++ b/apps/web/lib/settings/integration-setting.tsx @@ -27,7 +27,7 @@ export const IntegrationSetting = () => { }, []); const queries = new URLSearchParams(params || {}); - const url = `https://github.com/apps/${GITHUB_APP_NAME}/installations/new?${queries.toString()}`; + const url = `https://github.com/apps/${GITHUB_APP_NAME.value}/installations/new?${queries.toString()}`; const { activeTeam } = useOrganizationTeams(); From e4df6d2899b15128b2d0352c4cbf12c0ee3b1e21 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Mon, 11 Dec 2023 23:40:36 +0000 Subject: [PATCH 24/34] tiny changes --- apps/web/app/env.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/web/app/env.ts b/apps/web/app/env.ts index d9a236b41..f6a5d746c 100644 --- a/apps/web/app/env.ts +++ b/apps/web/app/env.ts @@ -14,6 +14,15 @@ type ReturnedType = { readonly value: T extends string ? string : InferValue; }; +/** + * This function loads only env variables which start with NEXT_PUBLIC_* + * + * Usefull to get the latest value of variable at runtime instead of buildtime + * + * @param name + * @param options + * @returns + */ export function getNextPublicEnv>(name: string, options?: O): ReturnedType { return { get value() { From 586b63fbac2db1b24d5bcff0b782bc97ff481889 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Tue, 12 Dec 2023 00:11:17 +0000 Subject: [PATCH 25/34] feat: Update environment variable retrieval in codebase --- apps/web/app/constants.ts | 6 ++++-- apps/web/app/services/client/api/employee.ts | 2 +- apps/web/pages/_app.tsx | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index edb86fd19..7ba67c7e4 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -33,7 +33,9 @@ export const RECAPTCHA_SITE_KEY = getNextPublicEnv('NEXT_PUBLIC_CAPTCHA_SITE_KEY export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; export const GAUZY_API_SERVER_URL = process.env.GAUZY_API_SERVER_URL || 'https://api.gauzy.co/api'; +export const GAUZY_API_BASE_SERVER_URL = getNextPublicEnv('NEXT_PUBLIC_GAUZY_API_SERVER_URL', 'https://api.gauzy.co'); +// Invite export const INVITE_CALLBACK_URL = process.env.INVITE_CALLBACK_URL || 'https://app.ever.team/auth/passcode'; export const INVITE_CALLBACK_PATH = '/auth/passcode'; export const VERIFY_EMAIL_CALLBACK_URL = process.env.VERIFY_EMAIL_CALLBACK_URL || 'https://app.ever.team/verify-email'; @@ -88,8 +90,8 @@ export const BOARD_FIREBASE_CONFIG = getNextPublicEnv('NEXT_PUBLIC_BOARD_FIREBAS // Jitsu export const jitsuConfiguration: () => JitsuOptions = () => ({ - host: process.env.NEXT_PUBLIC_JITSU_BROWSER_URL || '', - writeKey: process.env.NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY || '', + host: getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_URL', '').value, + writeKey: getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY', '').value, // if enabled - events will be sent to the console but no data sent to Jitsu. // Strange this is not mentioned in the documentation https://github.com/jitsucom/jitsu/blob/35c4ecaff54d61a87853381cb17262b7bfbd4a6e/libs/jitsu-js/src/jitsu.ts#L40 echoEvents: false, diff --git a/apps/web/app/services/client/api/employee.ts b/apps/web/app/services/client/api/employee.ts index 54f942a91..127f09a31 100644 --- a/apps/web/app/services/client/api/employee.ts +++ b/apps/web/app/services/client/api/employee.ts @@ -6,7 +6,7 @@ export async function getWorkingEmployeesAPI(tenantId: string, organizationId: s 'where[organizationId]': organizationId, 'relations[0]': 'user' }; - const query = new URLSearchParams(params); + const query = new URLSearchParams(params); const endpoint = process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? `/employee/pagination?${query.toString()}` diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index 1e5d661c8..5e2b0137e 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -1,5 +1,5 @@ /* eslint-disable no-mixed-spaces-and-tabs */ -import { loadNextPublicEnvs, setNextPublicEnv } from '@app/env'; +import { getNextPublicEnv, loadNextPublicEnvs, setNextPublicEnv } from '@app/env'; import { GA_MEASUREMENT_ID, jitsuConfiguration } from '@app/constants'; import { JitsuProvider } from '@jitsu/jitsu-react'; import { Analytics } from '@vercel/analytics/react'; @@ -85,8 +85,8 @@ const MyApp = ({ Component, pageProps }: AppProps) => { MyApp.getInitialProps = async ({ Component, ctx }: { Component: NextPage; ctx: NextPageContext }) => { // Recover environment variables - const jitsuHost = process.env.NEXT_PUBLIC_JITSU_BROWSER_URL; - const jitsuWriteKey = process.env.NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY; + const jitsuHost = getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_URL').value; + const jitsuWriteKey = getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY').value; const jitsuConf = jitsuConfiguration(); From 955696905030fc005450428c165962206f2348fc Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Tue, 12 Dec 2023 00:15:53 +0000 Subject: [PATCH 26/34] feat: update Chatwoot API key constant --- apps/web/app/constants.ts | 4 ++++ apps/web/lib/features/integrations/chatwoot/index.tsx | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 7ba67c7e4..822206cc6 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -32,6 +32,7 @@ export const ACTIVE_PROJECT_COOKIE_NAME = 'auth-active-project'; export const RECAPTCHA_SITE_KEY = getNextPublicEnv('NEXT_PUBLIC_CAPTCHA_SITE_KEY'); export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; +// Gauzy Server URL export const GAUZY_API_SERVER_URL = process.env.GAUZY_API_SERVER_URL || 'https://api.gauzy.co/api'; export const GAUZY_API_BASE_SERVER_URL = getNextPublicEnv('NEXT_PUBLIC_GAUZY_API_SERVER_URL', 'https://api.gauzy.co'); @@ -42,6 +43,9 @@ export const VERIFY_EMAIL_CALLBACK_URL = process.env.VERIFY_EMAIL_CALLBACK_URL | export const VERIFY_EMAIL_CALLBACK_PATH = '/verify-email'; export const GA_MEASUREMENT_ID = getNextPublicEnv('NEXT_PUBLIC_GA_MEASUREMENT_ID'); +// Chatwoot +export const CHATWOOT_API_KEY = getNextPublicEnv('NEXT_PUBLIC_CHATWOOT_API_KEY'); + export const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS || 'noreply@ever.team'; export const SMTP_HOST = process.env.SMTP_HOST || ''; export const SMTP_PORT = process.env.SMTP_PORT || ''; diff --git a/apps/web/lib/features/integrations/chatwoot/index.tsx b/apps/web/lib/features/integrations/chatwoot/index.tsx index 9bcce5240..849acf12e 100644 --- a/apps/web/lib/features/integrations/chatwoot/index.tsx +++ b/apps/web/lib/features/integrations/chatwoot/index.tsx @@ -1,3 +1,4 @@ +import { CHATWOOT_API_KEY } from '@app/constants'; import React, { useEffect } from 'react'; declare global { @@ -9,7 +10,7 @@ declare global { export default function ChatwootWidget() { useEffect(() => { - const websiteToken = process.env.NEXT_PUBLIC_CHATWOOT_API_KEY; + const websiteToken = CHATWOOT_API_KEY.value; if (!websiteToken) { return; } From 539508321d910753af1734ae16970f8362b3e21b Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Tue, 12 Dec 2023 04:25:28 +0100 Subject: [PATCH 27/34] feat: add kanban skeleton --- .../shared/skeleton/KanbanBoardSkeleton.tsx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx diff --git a/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx b/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx new file mode 100644 index 000000000..faa53b1a5 --- /dev/null +++ b/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx @@ -0,0 +1,40 @@ +import Skeleton from "react-loading-skeleton"; + +const KanbanBoardSkeleton = () => { + + let columns = Array.from(Array(3)); + + let tasks = Array.from(Array(2)); + + return ( + <> +
+ {columns.map((_, index: number)=> { + return ( + <> +
+ + +
+ {tasks.map((_, index: number)=> { + return ( + <> + + + ) + })} + + +
+
+ + ) + })} +
+ + ) +} + +export default KanbanBoardSkeleton; \ No newline at end of file From f009b6d1966ba1615b21f18771bc498c84632204 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Tue, 12 Dec 2023 04:26:01 +0100 Subject: [PATCH 28/34] feat:add skeleton to kanban board --- apps/web/pages/kanban/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/pages/kanban/index.tsx b/apps/web/pages/kanban/index.tsx index 592075453..9887bb646 100644 --- a/apps/web/pages/kanban/index.tsx +++ b/apps/web/pages/kanban/index.tsx @@ -1,4 +1,5 @@ import { useKanban } from "@app/hooks/features/useKanban"; +import KanbanBoardSkeleton from "@components/shared/skeleton/KanbanBoardSkeleton"; import { withAuthentication } from "lib/app/authenticator"; import { KanbanView } from "lib/features/team-members-kanban-view" import { MainLayout } from "lib/layout"; @@ -13,7 +14,7 @@ const Kanban= () => { {Object.keys(data).length > 0 ? : - null + } From 35f49d2013473f46cec950b2ba0cd489907242e7 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Tue, 12 Dec 2023 06:31:47 +0000 Subject: [PATCH 29/34] Refactor type names to improve clarity --- apps/web/app/env.ts | 4 ++-- apps/web/pages/_app.tsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/web/app/env.ts b/apps/web/app/env.ts index f6a5d746c..aed8b2b9c 100644 --- a/apps/web/app/env.ts +++ b/apps/web/app/env.ts @@ -2,11 +2,11 @@ const NEXT_PUBLIC_ENVS: { value: Env } = { value: {} }; type Env = Record; -type Poptions = { +type OptionObject = { default?: string; map?: (value: string | undefined) => T; }; -type Options = string | Poptions; +type Options = string | OptionObject; type InferValue = T extends { map: (value: any) => infer U } ? U : string | undefined; diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index 5e2b0137e..f874e4543 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -19,7 +19,6 @@ import 'react-loading-skeleton/dist/skeleton.css'; import '../styles/globals.css'; const MyApp = ({ Component, pageProps }: AppProps) => { - // Set Envs to availabe on client side setNextPublicEnv(pageProps.envs); const jitsuConf = pageProps?.jitsuConf; From c8602d78478bfce8c5ad428734d0108c80d15ef1 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Tue, 12 Dec 2023 06:50:11 +0000 Subject: [PATCH 30/34] fixed spell errors --- apps/web/app/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/env.ts b/apps/web/app/env.ts index aed8b2b9c..2c59d1c25 100644 --- a/apps/web/app/env.ts +++ b/apps/web/app/env.ts @@ -17,7 +17,7 @@ type ReturnedType = { /** * This function loads only env variables which start with NEXT_PUBLIC_* * - * Usefull to get the latest value of variable at runtime instead of buildtime + * Useful to get the latest value of variable at runtime instead of build time * * @param name * @param options From 1fa32ef255e6c54a59b713e2df06c07934367604 Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Tue, 12 Dec 2023 08:27:19 +0100 Subject: [PATCH 31/34] update:add key to fragment --- .../shared/skeleton/KanbanBoardSkeleton.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx b/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx index faa53b1a5..9a0ee2e96 100644 --- a/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx +++ b/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx @@ -1,3 +1,4 @@ +import React from "react"; import Skeleton from "react-loading-skeleton"; const KanbanBoardSkeleton = () => { @@ -13,23 +14,23 @@ const KanbanBoardSkeleton = () => { > {columns.map((_, index: number)=> { return ( - <> -
+ +
{tasks.map((_, index: number)=> { return ( - <> - - + + + ) })}
- + ) })}
From c6caf50ab76c2983930011bfed1859243362c376 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Tue, 12 Dec 2023 07:27:22 +0000 Subject: [PATCH 32/34] tiny improvements --- apps/web/pages/_app.tsx | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index f874e4543..e2c9b958a 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -4,6 +4,7 @@ import { GA_MEASUREMENT_ID, jitsuConfiguration } from '@app/constants'; import { JitsuProvider } from '@jitsu/jitsu-react'; import { Analytics } from '@vercel/analytics/react'; import { AppState } from 'lib/app/init-state'; +import type { JitsuOptions } from '@jitsu/jitsu-react/dist/useJitsu'; import ChatwootWidget from 'lib/features/integrations/chatwoot'; import { NextPage, NextPageContext } from 'next'; import { ThemeProvider } from 'next-themes'; @@ -18,7 +19,14 @@ import i18n from '../ni18n.config'; import 'react-loading-skeleton/dist/skeleton.css'; import '../styles/globals.css'; -const MyApp = ({ Component, pageProps }: AppProps) => { +type MyAppProps = { + jitsuConf?: JitsuOptions; + jitsuHost?: string; + envs: Record; + user?: any; +}; + +const MyApp = ({ Component, pageProps }: AppProps) => { setNextPublicEnv(pageProps.envs); const jitsuConf = pageProps?.jitsuConf; @@ -53,11 +61,11 @@ const MyApp = ({ Component, pageProps }: AppProps) => { options={ isJitsuEnvsPresent ? { - host: jitsuConf.host ?? '', - writeKey: jitsuConf.writeKey ?? undefined, - debug: jitsuConf.debug, - cookieDomain: jitsuConf.cookieDomain ?? undefined, - echoEvents: jitsuConf.echoEvents + host: jitsuConf?.host ?? '', + writeKey: jitsuConf?.writeKey ?? undefined, + debug: jitsuConf?.debug, + cookieDomain: jitsuConf?.cookieDomain ?? undefined, + echoEvents: jitsuConf?.echoEvents } : { disabled: true From 68fd446b1dc410f75994f3ef378a5be9a751166a Mon Sep 17 00:00:00 2001 From: maceteligolden Date: Tue, 12 Dec 2023 08:44:32 +0100 Subject: [PATCH 33/34] fix:resolve spacing issue and variable type --- .../shared/skeleton/KanbanBoardSkeleton.tsx | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx b/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx index 9a0ee2e96..523481c5b 100644 --- a/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx +++ b/apps/web/components/shared/skeleton/KanbanBoardSkeleton.tsx @@ -3,9 +3,9 @@ import Skeleton from "react-loading-skeleton"; const KanbanBoardSkeleton = () => { - let columns = Array.from(Array(3)); + const columns = Array.from(Array(3)); - let tasks = Array.from(Array(2)); + const tasks = Array.from(Array(2)); return ( <> @@ -14,22 +14,22 @@ const KanbanBoardSkeleton = () => { > {columns.map((_, index: number)=> { return ( - -
- + +
+ -
- {tasks.map((_, index: number)=> { - return ( - - - - ) - })} +
+ {tasks.map((_, index: number)=> { + return ( + + + + ) + })} - + +
-
) })} From 3e1a9ff69422e53b728bc251b06e5ad7a74ce16b Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Tue, 12 Dec 2023 10:03:12 +0000 Subject: [PATCH 34/34] feat: Update public environment variable --- apps/web/app/constants.ts | 57 ++++++++++++++----- apps/web/app/env.ts | 8 +-- apps/web/app/hooks/features/useImageAssets.ts | 3 +- apps/web/app/services/client/api/auth.ts | 3 +- apps/web/app/services/client/api/employee.ts | 7 +-- apps/web/app/services/client/api/invite.ts | 8 +-- apps/web/app/services/client/api/languages.ts | 3 +- .../services/client/api/organization-team.ts | 5 +- apps/web/app/services/client/api/tasks.ts | 7 ++- apps/web/app/services/client/api/timer.ts | 7 +-- apps/web/app/services/client/axios.ts | 21 +++++-- apps/web/lib/app/init-state.tsx | 2 +- apps/web/lib/settings/icon-items.tsx | 3 +- 13 files changed, 89 insertions(+), 45 deletions(-) diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index 822206cc6..5eb9f8f50 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -29,22 +29,34 @@ export const NO_TEAM_POPUP_SHOW_COOKIE_NAME = 'no-team-popup-show'; export const ACTIVE_PROJECT_COOKIE_NAME = 'auth-active-project'; // Recaptcha -export const RECAPTCHA_SITE_KEY = getNextPublicEnv('NEXT_PUBLIC_CAPTCHA_SITE_KEY'); +export const RECAPTCHA_SITE_KEY = getNextPublicEnv( + 'NEXT_PUBLIC_CAPTCHA_SITE_KEY', + process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY +); export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; // Gauzy Server URL export const GAUZY_API_SERVER_URL = process.env.GAUZY_API_SERVER_URL || 'https://api.gauzy.co/api'; -export const GAUZY_API_BASE_SERVER_URL = getNextPublicEnv('NEXT_PUBLIC_GAUZY_API_SERVER_URL', 'https://api.gauzy.co'); +export const GAUZY_API_BASE_SERVER_URL = getNextPublicEnv( + 'NEXT_PUBLIC_GAUZY_API_SERVER_URL', + process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL +); // Invite export const INVITE_CALLBACK_URL = process.env.INVITE_CALLBACK_URL || 'https://app.ever.team/auth/passcode'; export const INVITE_CALLBACK_PATH = '/auth/passcode'; export const VERIFY_EMAIL_CALLBACK_URL = process.env.VERIFY_EMAIL_CALLBACK_URL || 'https://app.ever.team/verify-email'; export const VERIFY_EMAIL_CALLBACK_PATH = '/verify-email'; -export const GA_MEASUREMENT_ID = getNextPublicEnv('NEXT_PUBLIC_GA_MEASUREMENT_ID'); +export const GA_MEASUREMENT_ID = getNextPublicEnv( + 'NEXT_PUBLIC_GA_MEASUREMENT_ID', + process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID +); // Chatwoot -export const CHATWOOT_API_KEY = getNextPublicEnv('NEXT_PUBLIC_CHATWOOT_API_KEY'); +export const CHATWOOT_API_KEY = getNextPublicEnv( + 'NEXT_PUBLIC_CHATWOOT_API_KEY', + process.env.NEXT_PUBLIC_CHATWOOT_API_KEY +); export const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS || 'noreply@ever.team'; export const SMTP_HOST = process.env.SMTP_HOST || ''; @@ -52,7 +64,12 @@ export const SMTP_PORT = process.env.SMTP_PORT || ''; export const SMTP_SECURE = process.env.SMTP_SECURE || ''; export const SMTP_USERNAME = process.env.SMTP_USERNAME || ''; export const SMTP_PASSWORD = process.env.SMTP_PASSWORD || ''; -export const DISABLE_AUTO_REFRESH = getNextPublicEnv('NEXT_PUBLIC_DISABLE_AUTO_REFRESH'); +export const DISABLE_AUTO_REFRESH = getNextPublicEnv('NEXT_PUBLIC_DISABLE_AUTO_REFRESH', { + default: process.env.NEXT_PUBLIC_DISABLE_AUTO_REFRESH, + map(value) { + return value === 'true'; + } +}); export const APP_NAME = process.env.APP_NAME || 'Ever Teams'; export const APP_SIGNATURE = process.env.APP_SIGNATURE || 'Ever Teams'; @@ -72,30 +89,41 @@ export const smtpConfiguration: () => I_SMTPRequest = () => ({ // Cookies export const COOKIE_DOMAINS = getNextPublicEnv('NEXT_PUBLIC_COOKIE_DOMAINS', { - default: 'ever.team', + default: process.env.NEXT_PUBLIC_COOKIE_DOMAINS || 'ever.team', map(value) { return value?.split(',').map((d) => d.trim()) || []; } }); // MEET Constants -export const MEET_DOMAIN = getNextPublicEnv('NEXT_PUBLIC_MEET_DOMAIN', 'meet.ever.team'); +export const MEET_DOMAIN = getNextPublicEnv( + 'NEXT_PUBLIC_MEET_DOMAIN', + process.env.NEXT_PUBLIC_MEET_DOMAIN || 'meet.ever.team' +); export const MEET_JWT_APP_ID = process.env.MEET_JWT_APP_ID || 'ever_teams'; export const MEET_JWT_APP_SECRET = process.env.MEET_JWT_APP_SECRET; export const MEET_JWT_TOKEN_COOKIE_NAME = 'meet-jwt-session'; // BOARD board -export const BOARD_APP_DOMAIN = getNextPublicEnv('NEXT_PUBLIC_BOARD_APP_DOMAIN', 'https://board.ever.team'); +export const BOARD_APP_DOMAIN = getNextPublicEnv( + 'NEXT_PUBLIC_BOARD_APP_DOMAIN', + process.env.NEXT_PUBLIC_BOARD_APP_DOMAIN || 'https://board.ever.team' +); + export const BOARD_BACKEND_POST_URL = getNextPublicEnv( 'NEXT_PUBLIC_BOARD_BACKEND_POST_URL', - 'https://jsonboard.ever.team/api/v2/post/' + process.env.NEXT_PUBLIC_BOARD_BACKEND_POST_URL || 'https://jsonboard.ever.team/api/v2/post/' +); +export const BOARD_FIREBASE_CONFIG = getNextPublicEnv( + 'NEXT_PUBLIC_BOARD_FIREBASE_CONFIG', + process.env.NEXT_PUBLIC_BOARD_FIREBASE_CONFIG ); -export const BOARD_FIREBASE_CONFIG = getNextPublicEnv('NEXT_PUBLIC_BOARD_FIREBASE_CONFIG'); // Jitsu export const jitsuConfiguration: () => JitsuOptions = () => ({ - host: getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_URL', '').value, - writeKey: getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY', '').value, + host: getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_URL', process.env.NEXT_PUBLIC_JITSU_BROWSER_URL).value, + writeKey: getNextPublicEnv('NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY', process.env.NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY) + .value, // if enabled - events will be sent to the console but no data sent to Jitsu. // Strange this is not mentioned in the documentation https://github.com/jitsucom/jitsu/blob/35c4ecaff54d61a87853381cb17262b7bfbd4a6e/libs/jitsu-js/src/jitsu.ts#L40 echoEvents: false, @@ -103,7 +131,10 @@ export const jitsuConfiguration: () => JitsuOptions = () => ({ }); // Github Integration -export const GITHUB_APP_NAME = getNextPublicEnv('NEXT_PUBLIC_GITHUB_APP_NAME', 'ever-github'); +export const GITHUB_APP_NAME = getNextPublicEnv( + 'NEXT_PUBLIC_GITHUB_APP_NAME', + process.env.NEXT_PUBLIC_GITHUB_APP_NAME || 'ever-github' +); // Application Languages export const APPLICATION_LANGUAGES = [ diff --git a/apps/web/app/env.ts b/apps/web/app/env.ts index 2c59d1c25..1da87ec87 100644 --- a/apps/web/app/env.ts +++ b/apps/web/app/env.ts @@ -15,9 +15,9 @@ type ReturnedType = { }; /** - * This function loads only env variables which start with NEXT_PUBLIC_* + * This function only loads environment variables starting with NEXT_PUBLIC_* * - * Useful to get the latest value of variable at runtime instead of build time + * Useful for getting the latest value of the variable at runtime rather than at build time * * @param name * @param options @@ -26,9 +26,9 @@ type ReturnedType = { export function getNextPublicEnv>(name: string, options?: O): ReturnedType { return { get value() { - let value = typeof options === 'string' ? options : options?.default; - value = NEXT_PUBLIC_ENVS.value[name] || value; + const defaultValue = typeof options === 'string' ? options : options?.default; + let value = NEXT_PUBLIC_ENVS.value[name] || defaultValue; if (typeof options === 'object' && options.map) { value = options.map(value) as any; } diff --git a/apps/web/app/hooks/features/useImageAssets.ts b/apps/web/app/hooks/features/useImageAssets.ts index fac4dd61d..7164968e7 100644 --- a/apps/web/app/hooks/features/useImageAssets.ts +++ b/apps/web/app/hooks/features/useImageAssets.ts @@ -1,6 +1,7 @@ import { getAccessTokenCookie } from '@app/helpers'; import { useCallback, useState } from 'react'; import axios, { AxiosResponse } from 'axios'; +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; export function useImageAssets() { const [loading, setLoading] = useState(false); @@ -15,7 +16,7 @@ export function useImageAssets() { setLoading(true); return axios - .post(process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL + `/api/image-assets/upload/${folder}`, formData, { + .post(GAUZY_API_BASE_SERVER_URL.value + `/api/image-assets/upload/${folder}`, formData, { headers: { 'tenant-id': tenantId, authorization: `Bearer ${bearer_token}` diff --git a/apps/web/app/services/client/api/auth.ts b/apps/web/app/services/client/api/auth.ts index e45048331..5b1ee2b91 100644 --- a/apps/web/app/services/client/api/auth.ts +++ b/apps/web/app/services/client/api/auth.ts @@ -2,6 +2,7 @@ import { getRefreshTokenCookie } from '@app/helpers/cookies'; import { ISuccessResponse } from '@app/interfaces'; import { ILoginResponse, IRegisterDataAPI, ISigninEmailConfirmResponse } from '@app/interfaces/IAuthentication'; import api, { get } from '../axios'; +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; export const signInWithEmailAndCodeAPI = (email: string, code: string) => { return api.post(`/auth/login`, { @@ -44,7 +45,7 @@ export const getAuthenticatedUserDataAPI = async () => { const endpoint = `/user/me?${query.toString()}`; const data = await get(endpoint, true); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; }; export const verifyUserEmailByCodeAPI = (code: string) => { diff --git a/apps/web/app/services/client/api/employee.ts b/apps/web/app/services/client/api/employee.ts index 127f09a31..eb2d6559d 100644 --- a/apps/web/app/services/client/api/employee.ts +++ b/apps/web/app/services/client/api/employee.ts @@ -1,3 +1,4 @@ +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; import { get } from '../axios'; export async function getWorkingEmployeesAPI(tenantId: string, organizationId: string) { @@ -8,10 +9,8 @@ export async function getWorkingEmployeesAPI(tenantId: string, organizationId: s }; const query = new URLSearchParams(params); - const endpoint = process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL - ? `/employee/pagination?${query.toString()}` - : '/employee/working'; + const endpoint = GAUZY_API_BASE_SERVER_URL.value ? `/employee/pagination?${query.toString()}` : '/employee/working'; const data = await get(endpoint, true, { tenantId }); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } diff --git a/apps/web/app/services/client/api/invite.ts b/apps/web/app/services/client/api/invite.ts index 73e46035c..4bac1c949 100644 --- a/apps/web/app/services/client/api/invite.ts +++ b/apps/web/app/services/client/api/invite.ts @@ -1,6 +1,6 @@ import { PaginationResponse } from '@app/interfaces/IDataResponse'; import { IInvitation, MyInvitationActionEnum, CreateResponse, IInviteCreate, IRole } from '@app/interfaces'; -import { INVITE_CALLBACK_URL } from '@app/constants'; +import { GAUZY_API_BASE_SERVER_URL, INVITE_CALLBACK_URL } from '@app/constants'; import api, { get, post } from '../axios'; import { AxiosResponse } from 'axios'; @@ -41,7 +41,7 @@ export async function inviteByEmailsAPI(data: IIInviteRequest, tenantId: string) // for not direct call we need to adjust data to include name and email only const fetchData = await post(endpoint, dataToInviteUser, true, { tenantId }); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? fetchData.data : fetchData; + return GAUZY_API_BASE_SERVER_URL.value ? fetchData.data : fetchData; } export async function getTeamInvitationsAPI(tenantId: string, organizationId: string, role: string, teamId: string) { @@ -56,7 +56,7 @@ export async function getTeamInvitationsAPI(tenantId: string, organizationId: st const endpoint = `/invite?${query.toString()}`; const data = await get(endpoint, true, { tenantId }); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } export function removeTeamInvitationsAPI(invitationId: string) { @@ -73,7 +73,7 @@ export async function getMyInvitationsAPI(tenantId: string) { const endpoint = '/invite/me'; const data = await get(endpoint, true, { tenantId }); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } export function acceptRejectMyInvitationsAPI(invitationId: string, action: MyInvitationActionEnum) { diff --git a/apps/web/app/services/client/api/languages.ts b/apps/web/app/services/client/api/languages.ts index 48a158c1f..15c7294e7 100644 --- a/apps/web/app/services/client/api/languages.ts +++ b/apps/web/app/services/client/api/languages.ts @@ -1,8 +1,9 @@ +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; import { get } from '../axios'; export async function getLanguageListAPI(is_system: boolean) { const endpoint = `/languages?is_system=${is_system}`; const data = await get(endpoint, true); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } diff --git a/apps/web/app/services/client/api/organization-team.ts b/apps/web/app/services/client/api/organization-team.ts index f9222f3b0..b2ea8e31f 100644 --- a/apps/web/app/services/client/api/organization-team.ts +++ b/apps/web/app/services/client/api/organization-team.ts @@ -9,6 +9,7 @@ import { } from '@app/interfaces'; import moment from 'moment'; import api, { get } from '../axios'; +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; export async function getOrganizationTeamsAPI(organizationId: string, tenantId: string) { const relations = [ @@ -36,7 +37,7 @@ export async function getOrganizationTeamsAPI(organizationId: string, tenantId: const endpoint = `/organization-team?${query.toString()}`; const data = await get(endpoint, true, { tenantId }); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } export function createOrganizationTeamAPI(name: string) { @@ -74,7 +75,7 @@ export async function getOrganizationTeamAPI(teamId: string, organizationId: str const endpoint = `/organization-team/${teamId}?${queries.toString()}`; const data = await get(endpoint, true); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } export function editOrganizationTeamAPI(data: IOrganizationTeamUpdate) { diff --git a/apps/web/app/services/client/api/tasks.ts b/apps/web/app/services/client/api/tasks.ts index 62c81e640..50fa49ae9 100644 --- a/apps/web/app/services/client/api/tasks.ts +++ b/apps/web/app/services/client/api/tasks.ts @@ -3,6 +3,7 @@ import { CreateResponse, DeleteResponse, PaginationResponse } from '@app/interfa import { ICreateTask, ITeamTask } from '@app/interfaces/ITask'; import { ITasksTimesheet } from '@app/interfaces/ITimer'; import api, { get } from '../axios'; +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; export function getTasksByIdAPI(taskId: string) { return api.get>(`/tasks/${taskId}`); @@ -40,7 +41,7 @@ export async function getTeamTasksAPI(organizationId: string, tenantId: string, const endpoint = `/tasks/team?${query.toString()}`; const data = await get(endpoint, true, { tenantId }); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } export function deleteTaskAPI(taskId: string) { @@ -61,7 +62,7 @@ export async function tasksTimesheetStatisticsAPI( organizationId: string, employeeId?: string ) { - if (process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL) { + if (GAUZY_API_BASE_SERVER_URL.value) { const employeesParams = employeeId ? [employeeId].reduce((acc: any, v, i) => { acc[`employeeIds[${i}]`] = v; @@ -109,7 +110,7 @@ export async function activeTaskTimesheetStatisticsAPI( organizationId: string, employeeId?: string ) { - if (process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL) { + if (GAUZY_API_BASE_SERVER_URL.value) { const employeesParams = employeeId ? [employeeId].reduce((acc: any, v, i) => { acc[`employeeIds[${i}]`] = v; diff --git a/apps/web/app/services/client/api/timer.ts b/apps/web/app/services/client/api/timer.ts index 45928cadb..59af332f2 100644 --- a/apps/web/app/services/client/api/timer.ts +++ b/apps/web/app/services/client/api/timer.ts @@ -1,14 +1,13 @@ import { ITimerStatus, IToggleTimerParams, TimerSource } from '@app/interfaces/ITimer'; import api, { get } from '../axios'; +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; export async function getTimerStatusAPI(tenantId: string, organizationId: string) { const params = new URLSearchParams({ tenantId, organizationId }); - const endpoint = process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL - ? `/timesheet/timer/status?${params.toString()}` - : '/timer/status'; + const endpoint = GAUZY_API_BASE_SERVER_URL.value ? `/timesheet/timer/status?${params.toString()}` : '/timer/status'; const data = await get(endpoint, true); - return process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL ? data.data : data; + return GAUZY_API_BASE_SERVER_URL.value ? data.data : data; } export function toggleTimerAPI(body: Pick) { diff --git a/apps/web/app/services/client/axios.ts b/apps/web/app/services/client/axios.ts index bd53becb2..0d210b312 100644 --- a/apps/web/app/services/client/axios.ts +++ b/apps/web/app/services/client/axios.ts @@ -1,5 +1,5 @@ /* eslint-disable no-mixed-spaces-and-tabs */ -import { API_BASE_URL, DEFAULT_APP_PATH } from '@app/constants'; +import { API_BASE_URL, DEFAULT_APP_PATH, GAUZY_API_BASE_SERVER_URL } from '@app/constants'; import { getAccessTokenCookie, getActiveTeamIdCookie } from '@app/helpers/cookies'; import axios, { AxiosResponse } from 'axios'; @@ -36,9 +36,9 @@ api.interceptors.response.use( ); const apiDirect = axios.create({ - baseURL: `${process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL}/api`, timeout: 60 * 1000 }); + apiDirect.interceptors.request.use( async (config: any) => { const cookie = getAccessTokenCookie(); @@ -53,6 +53,7 @@ apiDirect.interceptors.request.use( Promise.reject(error); } ); + apiDirect.interceptors.response.use( (response: AxiosResponse) => { return { @@ -78,8 +79,12 @@ function get( tenantId: string; } ) { - return isDirect && process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL + let baseURL: string | undefined = GAUZY_API_BASE_SERVER_URL.value; + baseURL = baseURL ? `${baseURL}/api` : undefined; + + return isDirect && baseURL ? apiDirect.get(endpoint, { + baseURL, headers: { ...(extras?.tenantId ? { 'tenant-id': extras?.tenantId } : {}) } @@ -95,8 +100,12 @@ function post( tenantId: string; } ) { - return isDirect && process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL + let baseURL: string | undefined = GAUZY_API_BASE_SERVER_URL.value; + baseURL = baseURL ? `${baseURL}/api` : undefined; + + return isDirect && baseURL ? apiDirect.post(endpoint, data, { + baseURL, headers: { ...(extras?.tenantId ? { 'tenant-id': extras?.tenantId } : {}) } @@ -104,6 +113,6 @@ function post( : api.post(endpoint, data); } -export default api; +export { get, post }; -export { apiDirect, get, post }; +export default api; diff --git a/apps/web/lib/app/init-state.tsx b/apps/web/lib/app/init-state.tsx index a0f96ce87..247e1f116 100644 --- a/apps/web/lib/app/init-state.tsx +++ b/apps/web/lib/app/init-state.tsx @@ -121,7 +121,7 @@ function InitState() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - return DISABLE_AUTO_REFRESH.value !== 'true' ? : <>; + return !DISABLE_AUTO_REFRESH.value ? : <>; } function useOneTimeLoad(func: () => void) { diff --git a/apps/web/lib/settings/icon-items.tsx b/apps/web/lib/settings/icon-items.tsx index d624e36e5..5ba87b2db 100644 --- a/apps/web/lib/settings/icon-items.tsx +++ b/apps/web/lib/settings/icon-items.tsx @@ -1,3 +1,4 @@ +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; import { IIcon } from '@app/interfaces'; import { clsxm } from '@app/utils'; import { DropdownItem } from 'lib/components'; @@ -93,7 +94,7 @@ export function IconItem({ export function generateIconList(iconFor: string, icons: string[]) { return icons.map((icon) => { return { - fullUrl: `${process.env.NEXT_PUBLIC_GAUZY_API_SERVER_URL}/public/ever-icons/${iconFor}/${icon}.svg`, + fullUrl: `${GAUZY_API_BASE_SERVER_URL.value}/public/ever-icons/${iconFor}/${icon}.svg`, path: `ever-icons/${iconFor}/${icon}.svg`, title: icon };