update user profile
parent
3bba897454
commit
bb1bf8ef0e
|
@ -12,8 +12,8 @@ import PageNotFound from "../../../features/PageNotFound";
|
||||||
import LessonPage from "../../../features/Lessons/LessonPage";
|
import LessonPage from "../../../features/Lessons/LessonPage";
|
||||||
import LessonPageEditor from "../../../features/Lessons/LessonPageEditor";
|
import LessonPageEditor from "../../../features/Lessons/LessonPageEditor";
|
||||||
import TeamCreateUser from "features/Team/CreateUser";
|
import TeamCreateUser from "features/Team/CreateUser";
|
||||||
import AccountSettings from "features/AccountSettings";
|
|
||||||
import Board from "features/Board";
|
import Board from "features/Board";
|
||||||
|
import UserProfile from "features/UserProfile";
|
||||||
|
|
||||||
export default function AppRoutes() {
|
export default function AppRoutes() {
|
||||||
return (
|
return (
|
||||||
|
@ -94,7 +94,7 @@ export default function AppRoutes() {
|
||||||
path={Constants.ROUTE_PATHS.ACCOUNT_SETTINGS}
|
path={Constants.ROUTE_PATHS.ACCOUNT_SETTINGS}
|
||||||
element={
|
element={
|
||||||
<MySupsenseFallback>
|
<MySupsenseFallback>
|
||||||
<AccountSettings />
|
<UserProfile />
|
||||||
</MySupsenseFallback>
|
</MySupsenseFallback>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||||
|
import { baseQueryWithErrorHandling } from "core/helper/api";
|
||||||
|
import { UserProfile } from "core/types/userProfile";
|
||||||
|
|
||||||
|
export const userProfileApi = createApi({
|
||||||
|
reducerPath: "userProfileApi",
|
||||||
|
baseQuery: baseQueryWithErrorHandling,
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
getUserProfile: builder.query<UserProfile, undefined>({
|
||||||
|
query: () => ({
|
||||||
|
url: "user/profile",
|
||||||
|
method: "GET",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { useGetUserProfileQuery } = userProfileApi;
|
|
@ -33,6 +33,7 @@ import {
|
||||||
deleteTeamMember,
|
deleteTeamMember,
|
||||||
updateTeamMemberRole,
|
updateTeamMemberRole,
|
||||||
} from "features/Team/teamSlice";
|
} from "features/Team/teamSlice";
|
||||||
|
import { setProfilePictureUrl } from "features/UserProfile/userProfileSlice";
|
||||||
|
|
||||||
interface WebSocketMessage {
|
interface WebSocketMessage {
|
||||||
Cmd: number;
|
Cmd: number;
|
||||||
|
@ -276,6 +277,9 @@ export function WebSocketMessageHandler(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WebSocketReceivedMessagesCmds.UserProfilePictureUpdated:
|
||||||
|
dispatch(setProfilePictureUrl(Body));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("Unknown message type:", Cmd);
|
console.error("Unknown message type:", Cmd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { organizationApi } from "core/services/organization";
|
||||||
import { teamSlice } from "features/Team/teamSlice";
|
import { teamSlice } from "features/Team/teamSlice";
|
||||||
import { lessonsSlice } from "features/Lessons/lessonsSlice";
|
import { lessonsSlice } from "features/Lessons/lessonsSlice";
|
||||||
import { lessonPageSlice } from "features/Lessons/LessonPage/lessonPageSlice";
|
import { lessonPageSlice } from "features/Lessons/LessonPage/lessonPageSlice";
|
||||||
|
import { userProfileApi } from "core/services/userProfile";
|
||||||
|
import { userProfileSlice } from "features/UserProfile/userProfileSlice";
|
||||||
|
|
||||||
const makeStore = (/* preloadedState */) => {
|
const makeStore = (/* preloadedState */) => {
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
|
@ -21,12 +23,15 @@ const makeStore = (/* preloadedState */) => {
|
||||||
[lessonPageSlice.reducerPath]: lessonPageSlice.reducer,
|
[lessonPageSlice.reducerPath]: lessonPageSlice.reducer,
|
||||||
[organizationApi.reducerPath]: organizationApi.reducer,
|
[organizationApi.reducerPath]: organizationApi.reducer,
|
||||||
[teamSlice.reducerPath]: teamSlice.reducer,
|
[teamSlice.reducerPath]: teamSlice.reducer,
|
||||||
|
[userProfileApi.reducerPath]: userProfileApi.reducer,
|
||||||
|
[userProfileSlice.reducerPath]: userProfileSlice.reducer,
|
||||||
},
|
},
|
||||||
// preloadedState,
|
// preloadedState,
|
||||||
middleware: (getDefaultMiddleware) =>
|
middleware: (getDefaultMiddleware) =>
|
||||||
getDefaultMiddleware().concat(
|
getDefaultMiddleware().concat(
|
||||||
lessonsApi.middleware,
|
lessonsApi.middleware,
|
||||||
organizationApi.middleware
|
organizationApi.middleware,
|
||||||
|
userProfileApi.middleware
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export interface UserProfile {
|
||||||
|
ProfilePictureUrl: string;
|
||||||
|
FirstName: string;
|
||||||
|
LastName: string;
|
||||||
|
Email: string;
|
||||||
|
RoleId: string;
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ export const Constants = {
|
||||||
ORGANIZATION_TEAM_CREATE_USER: "/team/create-user",
|
ORGANIZATION_TEAM_CREATE_USER: "/team/create-user",
|
||||||
ORGANIZATION_ROLES: "/roles",
|
ORGANIZATION_ROLES: "/roles",
|
||||||
ORGANIZATION_SETTINGS: "/settings",
|
ORGANIZATION_SETTINGS: "/settings",
|
||||||
ACCOUNT_SETTINGS: "/account",
|
ACCOUNT_SETTINGS: "/user-profile",
|
||||||
WHATS_NEW: "/whats-new",
|
WHATS_NEW: "/whats-new",
|
||||||
SUGGEST_FEATURE: "/suggest-feature",
|
SUGGEST_FEATURE: "/suggest-feature",
|
||||||
CONTACT_SUPPORT: "/contact-support",
|
CONTACT_SUPPORT: "/contact-support",
|
||||||
|
|
|
@ -19,6 +19,7 @@ enum WebSocketReceivedMessagesCmds {
|
||||||
LessonContentUpdated = 14,
|
LessonContentUpdated = 14,
|
||||||
LessonContentUpdatedPosition = 15,
|
LessonContentUpdatedPosition = 15,
|
||||||
LessonContentFileUpdated = 16,
|
LessonContentFileUpdated = 16,
|
||||||
|
UserProfilePictureUpdated = 17,
|
||||||
}
|
}
|
||||||
|
|
||||||
export { WebSocketSendMessagesCmds, WebSocketReceivedMessagesCmds };
|
export { WebSocketSendMessagesCmds, WebSocketReceivedMessagesCmds };
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
import {
|
|
||||||
Avatar,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Descriptions,
|
|
||||||
Divider,
|
|
||||||
Flex,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
Typography,
|
|
||||||
} from "antd";
|
|
||||||
import HeaderBar from "../../core/components/Header";
|
|
||||||
import MyBanner from "../../shared/components/MyBanner";
|
|
||||||
import { MyContainer } from "../../shared/components/MyContainer";
|
|
||||||
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 MyMiddleCard from "shared/components/MyMiddleCard";
|
|
||||||
import Meta from "antd/es/card/Meta";
|
|
||||||
|
|
||||||
export default function AccountSettings({ isAdmin }: { isAdmin?: boolean }) {
|
|
||||||
function AdminWrapper({ children }: { children: React.ReactNode }) {
|
|
||||||
if (!isAdmin) {
|
|
||||||
return <>{children}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form layout="vertical" style={{ marginTop: 24 }}>
|
|
||||||
{children}
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function TextItem({ value, name }: { value: string; name: string }) {
|
|
||||||
if (!isAdmin) {
|
|
||||||
return <>{value}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form.Item name={name} style={{ width: "100%" }} required>
|
|
||||||
<Input defaultValue={value} />
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<MyBanner
|
|
||||||
title="Account Settings"
|
|
||||||
subtitle="MANAGE"
|
|
||||||
headerBar={<HeaderBar />}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyMiddleCard title="My Profile">
|
|
||||||
<Flex vertical gap={16} style={{ paddingBottom: 16 }}>
|
|
||||||
<Card
|
|
||||||
styles={{
|
|
||||||
body: {
|
|
||||||
padding: 16,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Meta
|
|
||||||
avatar={
|
|
||||||
<Avatar
|
|
||||||
src={`${Constants.STATIC_CONTENT_ADDRESS}/demo/lesson_thumbnail.webp`}
|
|
||||||
size={56}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
title="Jorg Kreith"
|
|
||||||
description="Lead"
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
{/*<Card
|
|
||||||
styles={{
|
|
||||||
body: {
|
|
||||||
padding: 16,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Meta title="Personal Information" />
|
|
||||||
<Flex gap={16} style={{ marginTop: 24 }}>
|
|
||||||
<Flex vertical gap={24} flex={1}>
|
|
||||||
<Flex gap={8} vertical>
|
|
||||||
<TitleText>First name</TitleText>
|
|
||||||
<ValueText>Jorg</ValueText>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={8} vertical>
|
|
||||||
<TitleText>Email</TitleText>
|
|
||||||
<ValueText>julian@xx.com</ValueText>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
<Flex vertical gap={24} flex={1}>
|
|
||||||
<Flex gap={8} vertical>
|
|
||||||
<TitleText>Last name</TitleText>
|
|
||||||
<ValueText>Kreth</ValueText>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Card>*/}
|
|
||||||
<Card
|
|
||||||
styles={{
|
|
||||||
body: {
|
|
||||||
padding: 16,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AdminWrapper>
|
|
||||||
<Descriptions
|
|
||||||
title="Personal Information"
|
|
||||||
layout="vertical"
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
key: "1",
|
|
||||||
label: "First name",
|
|
||||||
children: <TextItem value="Jorg" name="firstName" />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "2",
|
|
||||||
label: "Last name",
|
|
||||||
children: <TextItem value="Kreth" name="lastName" />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "3",
|
|
||||||
label: "Email",
|
|
||||||
children: <TextItem value="julian@xx.com" name="email" />,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</AdminWrapper>
|
|
||||||
</Card>
|
|
||||||
</Flex>
|
|
||||||
</MyMiddleCard>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// TODO: sessions table
|
|
||||||
|
|
||||||
<Card
|
|
||||||
styles={{
|
|
||||||
body: {
|
|
||||||
padding: 16,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Meta title="Sessions" />
|
|
||||||
<Typography.Text>// Todoo</Typography.Text>
|
|
||||||
</Card>
|
|
||||||
*/
|
|
||||||
|
|
||||||
function TitleText({ children }: { children: React.ReactNode }) {
|
|
||||||
return (
|
|
||||||
<Typography.Text style={{ fontSize: 16, opacity: 0.4 }}>
|
|
||||||
{children}
|
|
||||||
</Typography.Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ValueText({ children }: { children: React.ReactNode }) {
|
|
||||||
return <Typography.Text style={{ fontSize: 16 }}>{children}</Typography.Text>;
|
|
||||||
}
|
|
|
@ -1,7 +1,21 @@
|
||||||
|
import { Button, Result } from "antd";
|
||||||
|
import { Constants } from "core/utils/utils";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { MyCenteredContainer } from "shared/components/MyContainer";
|
||||||
|
|
||||||
export default function PageNotFound() {
|
export default function PageNotFound() {
|
||||||
return (
|
return (
|
||||||
<>
|
<MyCenteredContainer>
|
||||||
<h1>PageNotFound</h1>
|
<Result
|
||||||
</>
|
status="404"
|
||||||
|
title="404"
|
||||||
|
subTitle="Sorry, the page you visited does not exist."
|
||||||
|
extra={
|
||||||
|
<Link to={Constants.ROUTE_PATHS.BOARD}>
|
||||||
|
<Button type="primary">Back Home</Button>
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</MyCenteredContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -199,7 +199,7 @@ function MediaCard({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={`${Constants.STATIC_CONTENT_ADDRESS}${
|
src={`${Constants.STATIC_CONTENT_ADDRESS}/${
|
||||||
appLogoUrl || Constants.DEMO_LOGO_URL
|
appLogoUrl || Constants.DEMO_LOGO_URL
|
||||||
}`}
|
}`}
|
||||||
alt="Company Logo"
|
alt="Company Logo"
|
||||||
|
@ -233,7 +233,7 @@ function MediaCard({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={`${Constants.STATIC_CONTENT_ADDRESS}${
|
src={`${Constants.STATIC_CONTENT_ADDRESS}/${
|
||||||
appBannerUrl || Constants.DEMO_BANNER_URL
|
appBannerUrl || Constants.DEMO_BANNER_URL
|
||||||
}`}
|
}`}
|
||||||
alt="Banner"
|
alt="Banner"
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Card,
|
||||||
|
Descriptions,
|
||||||
|
Flex,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Typography,
|
||||||
|
} from "antd";
|
||||||
|
import HeaderBar from "../../core/components/Header";
|
||||||
|
import MyBanner from "../../shared/components/MyBanner";
|
||||||
|
import { Constants } from "core/utils/utils";
|
||||||
|
import MyMiddleCard from "shared/components/MyMiddleCard";
|
||||||
|
import Meta from "antd/es/card/Meta";
|
||||||
|
import { useGetUserProfileQuery } from "core/services/userProfile";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import {
|
||||||
|
addWebSocketReconnectListener,
|
||||||
|
removeWebSocketReconnectListener,
|
||||||
|
} from "core/services/websocketService";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
email,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
profilePictureUrl,
|
||||||
|
roleId,
|
||||||
|
setEmail,
|
||||||
|
setFirstName,
|
||||||
|
setLastName,
|
||||||
|
setProfilePictureUrl,
|
||||||
|
setRoleId,
|
||||||
|
} from "./userProfileSlice";
|
||||||
|
import { tmpRoleNames } from "features/Roles";
|
||||||
|
import MyErrorResult from "shared/components/MyResult";
|
||||||
|
import MyUpload from "shared/components/MyUpload";
|
||||||
|
import { useMessage } from "core/context/MessageContext";
|
||||||
|
|
||||||
|
export default function UserProfile({ isAdmin }: { isAdmin?: boolean }) {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { success } = useMessage();
|
||||||
|
|
||||||
|
const dataProfilePictureUrl = useSelector(profilePictureUrl);
|
||||||
|
const dataFirstName = useSelector(firstName);
|
||||||
|
const dataLastName = useSelector(lastName);
|
||||||
|
const dataEmail = useSelector(email);
|
||||||
|
const dataRoleId = useSelector(roleId);
|
||||||
|
|
||||||
|
const { data, error, isLoading, refetch } = useGetUserProfileQuery(
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
refetchOnMountOrArgChange: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function AdminWrapper({ children }: { children: React.ReactNode }) {
|
||||||
|
if (!isAdmin) {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form layout="vertical" style={{ marginTop: 24 }}>
|
||||||
|
{children}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TextItem({ value, name }: { value: string; name: string }) {
|
||||||
|
if (!isAdmin) {
|
||||||
|
return <>{value}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item name={name} style={{ width: "100%" }} required>
|
||||||
|
<Input defaultValue={value} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
dispatch(setProfilePictureUrl(data.ProfilePictureUrl));
|
||||||
|
dispatch(setFirstName(data.FirstName));
|
||||||
|
dispatch(setLastName(data.LastName));
|
||||||
|
dispatch(setEmail(data.Email));
|
||||||
|
dispatch(setRoleId(data.RoleId));
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
addWebSocketReconnectListener(refetch);
|
||||||
|
|
||||||
|
return () => removeWebSocketReconnectListener(refetch);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MyBanner
|
||||||
|
title="Account Settings"
|
||||||
|
subtitle="MANAGE"
|
||||||
|
headerBar={<HeaderBar />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyMiddleCard title="My Profile" loading={isLoading}>
|
||||||
|
{error ? (
|
||||||
|
<MyErrorResult />
|
||||||
|
) : (
|
||||||
|
<Flex vertical gap={16} style={{ paddingBottom: 16 }}>
|
||||||
|
<Card
|
||||||
|
styles={{
|
||||||
|
body: {
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Meta
|
||||||
|
avatar={
|
||||||
|
<MyUpload
|
||||||
|
action={`/user/profile/picture`}
|
||||||
|
onChange={(info) => {
|
||||||
|
if (info.file.status === "done") {
|
||||||
|
success("Profile picture updated successfully");
|
||||||
|
|
||||||
|
dispatch(setProfilePictureUrl(info.file.response.Data));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
imgCropProps={{
|
||||||
|
aspect: 1 / 1,
|
||||||
|
children: <></>,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dataProfilePictureUrl === "" ? (
|
||||||
|
<Avatar size={56} style={{ backgroundColor: "#1677ff" }}>
|
||||||
|
{dataFirstName.charAt(0).toUpperCase()}
|
||||||
|
</Avatar>
|
||||||
|
) : (
|
||||||
|
<Avatar
|
||||||
|
src={`${Constants.STATIC_CONTENT_ADDRESS}/${dataProfilePictureUrl}`}
|
||||||
|
size={56}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</MyUpload>
|
||||||
|
}
|
||||||
|
title={`${dataFirstName} ${dataLastName}`}
|
||||||
|
description={tmpRoleNames[dataRoleId]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card
|
||||||
|
styles={{
|
||||||
|
body: {
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AdminWrapper>
|
||||||
|
<Descriptions
|
||||||
|
title="Personal Information"
|
||||||
|
layout="vertical"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: "1",
|
||||||
|
label: "First name",
|
||||||
|
children: (
|
||||||
|
<TextItem value={dataFirstName} name="firstName" />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "2",
|
||||||
|
label: "Last name",
|
||||||
|
children: (
|
||||||
|
<TextItem value={dataLastName} name="lastName" />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "3",
|
||||||
|
label: "Email",
|
||||||
|
children: <TextItem value={dataEmail} name="email" />,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</AdminWrapper>
|
||||||
|
</Card>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</MyMiddleCard>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO: sessions table
|
||||||
|
|
||||||
|
<Card
|
||||||
|
styles={{
|
||||||
|
body: {
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Meta title="Sessions" />
|
||||||
|
<Typography.Text>// Todoo</Typography.Text>
|
||||||
|
</Card>
|
||||||
|
*/
|
||||||
|
|
||||||
|
function TitleText({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<Typography.Text style={{ fontSize: 16, opacity: 0.4 }}>
|
||||||
|
{children}
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ValueText({ children }: { children: React.ReactNode }) {
|
||||||
|
return <Typography.Text style={{ fontSize: 16 }}>{children}</Typography.Text>;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
export const userProfileSlice = createSlice({
|
||||||
|
name: "userProfile",
|
||||||
|
initialState: {
|
||||||
|
profilePictureUrl: "",
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
email: "",
|
||||||
|
roleId: "",
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
setProfilePictureUrl: (state, action) => {
|
||||||
|
state.profilePictureUrl = action.payload;
|
||||||
|
},
|
||||||
|
setFirstName: (state, action) => {
|
||||||
|
state.firstName = action.payload;
|
||||||
|
},
|
||||||
|
setLastName: (state, action) => {
|
||||||
|
state.lastName = action.payload;
|
||||||
|
},
|
||||||
|
setEmail: (state, action) => {
|
||||||
|
state.email = action.payload;
|
||||||
|
},
|
||||||
|
setRoleId: (state, action) => {
|
||||||
|
state.roleId = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectors: {
|
||||||
|
profilePictureUrl: (state) => state.profilePictureUrl,
|
||||||
|
firstName: (state) => state.firstName,
|
||||||
|
lastName: (state) => state.lastName,
|
||||||
|
email: (state) => state.email,
|
||||||
|
roleId: (state) => state.roleId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
setEmail,
|
||||||
|
setFirstName,
|
||||||
|
setLastName,
|
||||||
|
setProfilePictureUrl,
|
||||||
|
setRoleId,
|
||||||
|
} = userProfileSlice.actions;
|
||||||
|
|
||||||
|
export const { profilePictureUrl, firstName, lastName, email, roleId } =
|
||||||
|
userProfileSlice.selectors;
|
|
@ -42,29 +42,39 @@ export default function MyUpload({
|
||||||
? accept.join(",")
|
? accept.join(",")
|
||||||
: (accept as string);
|
: (accept as string);
|
||||||
|
|
||||||
const MyUpload = () => (
|
|
||||||
<Upload
|
|
||||||
accept={acceptFileTypes}
|
|
||||||
maxCount={maxCount}
|
|
||||||
showUploadList={showUploadList}
|
|
||||||
headers={headers}
|
|
||||||
action={`${Constants.API_ADDRESS}${action}`}
|
|
||||||
onChange={(info) => {
|
|
||||||
if (onChange) onChange(info);
|
|
||||||
}}
|
|
||||||
beforeUpload={beforeUpload}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Upload>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (fileType === "video") {
|
if (fileType === "video") {
|
||||||
return <MyUpload />;
|
return (
|
||||||
|
<Upload
|
||||||
|
accept={acceptFileTypes}
|
||||||
|
maxCount={maxCount}
|
||||||
|
showUploadList={showUploadList}
|
||||||
|
headers={headers}
|
||||||
|
action={`${Constants.API_ADDRESS}${action}`}
|
||||||
|
onChange={(info) => {
|
||||||
|
if (onChange) onChange(info);
|
||||||
|
}}
|
||||||
|
beforeUpload={beforeUpload}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Upload>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImgCrop {...imgCropProps} rotationSlider>
|
<ImgCrop {...imgCropProps} rotationSlider>
|
||||||
<MyUpload />
|
<Upload
|
||||||
|
accept={acceptFileTypes}
|
||||||
|
maxCount={maxCount}
|
||||||
|
showUploadList={showUploadList}
|
||||||
|
headers={headers}
|
||||||
|
action={`${Constants.API_ADDRESS}${action}`}
|
||||||
|
onChange={(info) => {
|
||||||
|
if (onChange) onChange(info);
|
||||||
|
}}
|
||||||
|
beforeUpload={beforeUpload}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Upload>
|
||||||
</ImgCrop>
|
</ImgCrop>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue