diff --git a/src/App.tsx b/src/App.tsx index ae8672c..2b801dc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,8 @@ import { ConfigProvider, Layout, theme } from "antd"; import DashboardLayout from "./core/components/DashboardLayout"; import { darkMode, + primaryColor, + setPrimaryColor, setUserAuthenticated, userAuthenticated, } from "./core/reducers/appSlice"; @@ -19,6 +21,7 @@ function App() { const isDarkMode = useSelector(darkMode); const uAuthenticated = useSelector(userAuthenticated); + const primColor = useSelector(primaryColor); console.info( "\n %c LMS %c v1.0.0 %c \n", @@ -36,12 +39,13 @@ function App() { (async () => { try { const response = await myFetch({ - url: "/user", + url: "/app", method: "GET", }); if (response) { - dispatch(setUserAuthenticated(true)) + dispatch(setUserAuthenticated(true)); + dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`)); } } catch (error) {} })(); @@ -58,10 +62,13 @@ function App() { {uAuthenticated == null ? ( - + ) : uAuthenticated ? ( ) : ( diff --git a/src/core/reducers/appSlice.tsx b/src/core/reducers/appSlice.tsx index 8cdc465..fb87d49 100644 --- a/src/core/reducers/appSlice.tsx +++ b/src/core/reducers/appSlice.tsx @@ -5,6 +5,7 @@ export const appSlice = createSlice({ initialState: { darkMode: false, userAuthenticated: null, + primaryColor: "#1677FF", }, reducers: { setDarkMode: (state, action) => { @@ -12,14 +13,19 @@ export const appSlice = createSlice({ }, setUserAuthenticated: (state, action) => { state.userAuthenticated = action.payload; - } + }, + setPrimaryColor: (state, action) => { + state.primaryColor = action.payload; + }, }, selectors: { darkMode: (state) => state.darkMode, userAuthenticated: (state) => state.userAuthenticated, + primaryColor: (state) => state.primaryColor, }, -}) +}); -export const { setDarkMode, setUserAuthenticated } = appSlice.actions; +export const { setDarkMode, setUserAuthenticated, setPrimaryColor } = + appSlice.actions; -export const { darkMode, userAuthenticated } = appSlice.selectors; \ No newline at end of file +export const { darkMode, userAuthenticated, primaryColor } = appSlice.selectors; diff --git a/src/core/services/organization.ts b/src/core/services/organization.ts index 982e96f..83bd8c5 100644 --- a/src/core/services/organization.ts +++ b/src/core/services/organization.ts @@ -1,24 +1,35 @@ -import { createApi } from '@reduxjs/toolkit/query/react'; -import { baseQueryWithErrorHandling } from 'core/helper/api'; -import { TeamMember, OrganizationSettings } from 'core/types/organization'; +import { createApi } from "@reduxjs/toolkit/query/react"; +import { baseQueryWithErrorHandling } from "core/helper/api"; +import { TeamMember, OrganizationSettings } from "core/types/organization"; export const organizationApi = createApi({ - reducerPath: 'organizationApi', - baseQuery: baseQueryWithErrorHandling, - endpoints: (builder) => ({ - getTeam: builder.query({ - query: () => ({ - url: 'organization/team/members', - method: 'GET', - }), - }), - getOrganizationSettings: builder.query({ - query: () => ({ - url: 'organization/settings', - method: 'GET', - }), - }), + reducerPath: "organizationApi", + baseQuery: baseQueryWithErrorHandling, + endpoints: (builder) => ({ + getTeam: builder.query({ + query: () => ({ + url: "organization/team/members", + method: "GET", + }), }), + getOrganizationSettings: builder.query({ + query: () => ({ + url: "organization/settings", + method: "GET", + }), + }), + updateOrganizationSettings: builder.mutation({ + query: ({ primaryColor, companyName }) => ({ + url: "organization/settings", + method: "PATCH", + body: { PrimaryColor: primaryColor, CompanyName: companyName }, + }), + }), + }), }); -export const { useGetTeamQuery, useGetOrganizationSettingsQuery } = organizationApi; +export const { + useGetTeamQuery, + useGetOrganizationSettingsQuery, + useUpdateOrganizationSettingsMutation, +} = organizationApi; diff --git a/src/features/Settings/index.tsx b/src/features/Settings/index.tsx index d17c4aa..d78cb6f 100644 --- a/src/features/Settings/index.tsx +++ b/src/features/Settings/index.tsx @@ -1,4 +1,4 @@ -import { Button, Card, Divider, Flex, Form, Input, Typography } from "antd"; +import { Button, Card, Flex, Form, Input } from "antd"; import HeaderBar from "../../core/components/Header"; import MyBanner from "../../shared/components/MyBanner"; import { MyContainer } from "../../shared/components/MyContainer"; @@ -6,14 +6,19 @@ import { SaveOutlined } from "@ant-design/icons"; import MyUpload from "shared/components/MyUpload"; import { Constants } from "core/utils/utils"; import ColorPicker from "antd/es/color-picker"; -import { useGetOrganizationSettingsQuery } from "core/services/organization"; +import { + useGetOrganizationSettingsQuery, + useUpdateOrganizationSettingsMutation, +} from "core/services/organization"; import MyErrorResult from "shared/components/MyResult"; import { useForm } from "antd/es/form/Form"; -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; import { AggregationColor } from "antd/es/color-picker/color"; +import { useDispatch } from "react-redux"; +import { setPrimaryColor } from "core/reducers/appSlice"; type FieldType = { - primaryColor: string; + primaryColor: string | AggregationColor; companyName: string; subdomain: string; }; @@ -27,9 +32,29 @@ export default function Settings() { ); const [form] = useForm(); + const dispatch = useDispatch(); + const debounceRef = useRef(null); + const currentPrimaryColor = useRef(); + + const [updateOrganizationSettings, { isLoading: isUpdateSettingsLoading }] = + useUpdateOrganizationSettingsMutation(); const handleSave = (values: FieldType) => { - console.log(values); + const hexColor = + typeof values.primaryColor === "string" + ? values.primaryColor + : values.primaryColor.toHexString().split("#")[1]; + + try { + updateOrganizationSettings({ + primaryColor: hexColor, + companyName: values.companyName, + }); + + currentPrimaryColor.current = hexColor; + } catch (error) { + console.error(error); + } }; useEffect(() => { @@ -39,9 +64,21 @@ export default function Settings() { companyName: data.CompanyName, subdomain: data.Subdomain, }); + + currentPrimaryColor.current = data.PrimaryColor; } }, [data]); + useEffect(() => { + return () => { + dispatch(setPrimaryColor(currentPrimaryColor.current)); + + if (debounceRef.current) { + clearTimeout(debounceRef.current); + } + }; + }, []); + if (error) return ; return ( @@ -49,127 +86,111 @@ export default function Settings() { } /> - -
- } - type="text" - shape="circle" - size="large" - htmlType="submit" + + } + type="text" + shape="circle" + size="large" + htmlType="submit" + loading={isUpdateSettingsLoading} + /> + } + > + + name="primaryColor" label="Primary color"> + { + if (debounceRef.current) { + clearTimeout(debounceRef.current); + } + + debounceRef.current = setTimeout(() => { + dispatch(setPrimaryColor(color.toHexString())); + }, 600); + }} /> - } - > - - - - - Primary Color - - - - - - - - Company name - - - - - - - - Subdomain - - - - - - - - Logo - - { - if (info.file.status === "done") { - //onThumbnailChanged?.(); - console.log("done"); - } - }} - imgCropProps={{ - aspect: 1 / 1, - children: <>, - }} - > - Company Logo - - - - - - Thumbnail - - { - if (info.file.status === "done") { - //onThumbnailChanged?.(); - console.log("done"); - } + + name="companyName" label="Company name"> + + + name="subdomain" label="Subdomain"> + + + + { + if (info.file.status === "done") { + //onThumbnailChanged?.(); + console.log("done"); + } + }} + imgCropProps={{ + aspect: 1 / 1, + children: <>, + }} + > + Company Logo, - }} - > - Thumbnail - - - - - -
+ /> + + + + + + { + if (info.file.status === "done") { + //onThumbnailChanged?.(); + console.log("done"); + } + }} + imgCropProps={{ + aspect: 22 / 9, + children: <>, + }} + > + Thumbnail + + + +
);