diff --git a/frontend/src/components/QuickAddCartButton/QuickAddCartButton.tsx b/frontend/src/components/QuickAddCartButton/QuickAddCartButton.tsx
index 876859e16..364fe4e3c 100644
--- a/frontend/src/components/QuickAddCartButton/QuickAddCartButton.tsx
+++ b/frontend/src/components/QuickAddCartButton/QuickAddCartButton.tsx
@@ -1,8 +1,10 @@
import React from 'react';
import { useMutation, useQueryClient } from 'react-query';
+import { useSelector } from 'react-redux';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import { Tooltip } from 'antd';
import { addToUnplanned, removeCourse } from 'utils/api/plannerApi';
+import { RootState } from 'config/store';
import S from './styles';
type Props = {
@@ -14,6 +16,10 @@ type Props = {
const QuickAddCartButton = ({ courseCode, runMutate, planned }: Props) => {
const handleMutation = planned ? removeCourse : addToUnplanned;
+ const { theme } = useSelector((state: RootState) => state.settings);
+ const iconStyles = {
+ color: theme === 'light' ? '#000' : '#fff'
+ };
const queryClient = useQueryClient();
const mutation = useMutation(handleMutation, {
onMutate: () => planned,
@@ -37,7 +43,7 @@ const QuickAddCartButton = ({ courseCode, runMutate, planned }: Props) => {
size="small"
loading={mutation.isLoading}
shape="circle"
- icon={
}
+ icon={
}
/>
) : (
@@ -48,7 +54,7 @@ const QuickAddCartButton = ({ courseCode, runMutate, planned }: Props) => {
size="small"
loading={mutation.isLoading}
shape="circle"
- icon={
}
+ icon={
}
/>
);
diff --git a/frontend/src/components/ThemeToggle/ThemeToggle.tsx b/frontend/src/components/ThemeToggle/ThemeToggle.tsx
index 4137b3f0f..d4bd79589 100644
--- a/frontend/src/components/ThemeToggle/ThemeToggle.tsx
+++ b/frontend/src/components/ThemeToggle/ThemeToggle.tsx
@@ -15,8 +15,8 @@ const ThemeToggle = () => {
return (
}
- unCheckedChildren={
}
+ checkedChildren={
}
+ unCheckedChildren={
}
defaultChecked={theme === 'dark'}
onChange={() => dispatch(toggleTheme(theme === 'light' ? 'dark' : 'light'))}
style={toggleStyle}
diff --git a/frontend/src/config/axios.ts b/frontend/src/config/axios.ts
index a418b6847..c5f11dcb3 100644
--- a/frontend/src/config/axios.ts
+++ b/frontend/src/config/axios.ts
@@ -2,7 +2,7 @@ import axios from 'axios';
// fallback to localhost port 8000 if env variable is not specified
axios.defaults.baseURL =
- import.meta.env.VITE_BACKEND_API_BASE_URL || 'https://circlesapi.csesoc.app/';
+ import.meta.env.VITE_BACKEND_API_BASE_URL || 'https://circlesapi.devsoc.app/';
axios.defaults.headers.post['Content-Type'] = 'application/json';
diff --git a/frontend/src/config/constants.ts b/frontend/src/config/constants.ts
index be6c2a71a..78f1e8eed 100644
--- a/frontend/src/config/constants.ts
+++ b/frontend/src/config/constants.ts
@@ -7,7 +7,7 @@ export const CURR_YEAR = new Date().getFullYear();
export const TERM = `${CURR_YEAR + (getMostRecentPastTerm(CURR_YEAR).T === 3 ? 1 : 0)}-T${
(getMostRecentPastTerm(CURR_YEAR).T + 0) % 3
}`;
-export const TIMETABLE_API_URL = `https://timetable.csesoc.app/api/terms/${TERM}/courses`;
+export const TIMETABLE_API_URL = `https://timetable.devsoc.app/api/terms/${TERM}/courses`;
// Global colors - currently only being used in LiquidProgressChart
export const lightYellow = '#f9b01e';
diff --git a/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx b/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx
index a59d58e13..328cc7068 100644
--- a/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx
+++ b/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { useDispatch, useSelector } from 'react-redux';
import type { MenuProps } from 'antd';
@@ -84,7 +84,6 @@ const CourseMenu = ({ planner, courses, degree }: CourseMenuProps) => {
await queryClient.invalidateQueries({ queryKey: ['planner'] });
}
});
- const runMutate = (courseId: string) => courseMutation.mutate(courseId);
const dispatch = useDispatch();
const [menuData, setMenuData] = useState
({});
@@ -142,7 +141,14 @@ const CourseMenu = ({ planner, courses, degree }: CourseMenuProps) => {
useEffect(() => {
if (!courses || !structureQuery.isSuccess || !coursesStateQuery.isSuccess) return;
generateMenuData(structureQuery.data, coursesStateQuery.data);
- }, [planner, structureQuery, coursesStateQuery, generateMenuData, courses]);
+ }, [
+ courses,
+ coursesStateQuery.data,
+ coursesStateQuery.isSuccess,
+ generateMenuData,
+ structureQuery.data,
+ structureQuery.isSuccess
+ ]);
const sortSubgroups = (
item1: [string, MenuDataSubgroup[]],
@@ -162,54 +168,65 @@ const CourseMenu = ({ planner, courses, degree }: CourseMenuProps) => {
const sortCourses = (item1: MenuDataSubgroup, item2: MenuDataSubgroup) =>
item1.courseCode > item2.courseCode ? 1 : -1;
- const defaultOpenKeys = [Object.keys(menuData)[0]];
-
- let menuItems: MenuProps['items'];
- if (pageLoaded && structureQuery.isSuccess && courses) {
- const structure = structureQuery.data;
- menuItems = Object.entries(menuData).map(([groupKey, groupEntry]) => ({
- label: structure[groupKey].name ? `${groupKey} - ${structure[groupKey].name}` : groupKey,
- key: groupKey,
- children: Object.entries(groupEntry)
- .sort(sortSubgroups)
- .map(([subgroupKey, subGroupEntry]) => {
- const currUOC = coursesUnits ? coursesUnits[groupKey][subgroupKey].curr : 0;
- const totalUOC = coursesUnits ? coursesUnits[groupKey][subgroupKey].total : 0;
- if (subGroupEntry.length <= MAX_COURSES_OVERFLOW) defaultOpenKeys.push(subgroupKey);
- return {
- label: ,
- key: subgroupKey,
- disabled: !subGroupEntry.length, // disable submenu if there are no courses
- // check if there are courses to show collapsible submenu
- children: subGroupEntry.length
- ? subGroupEntry
- .sort(sortCourses)
- .filter(
- (course) =>
- course.unlocked ||
- courses[course.courseCode] !== undefined ||
- showLockedCourses
- )
- .map((course) => ({
- label: (
-
- ),
- // key is course code + groupKey + subgroupKey to differentiate as unique
- // course items in menu
- key: `${course.courseCode}-${groupKey}-${subgroupKey}`
- }))
- : null
- };
- })
- }));
- }
+ const defaultOpenKeys = useMemo(() => [Object.keys(menuData)[0]], [menuData]);
+ const menuItems: MenuProps['items'] = useMemo((): MenuProps['items'] => {
+ if (pageLoaded && structureQuery.isSuccess && courses) {
+ const structure = structureQuery.data;
+ return Object.entries(menuData).map(([groupKey, groupEntry]) => ({
+ label: structure[groupKey].name ? `${groupKey} - ${structure[groupKey].name}` : groupKey,
+ key: groupKey,
+ children: Object.entries(groupEntry)
+ .sort(sortSubgroups)
+ .map(([subgroupKey, subGroupEntry]) => {
+ const currUOC = coursesUnits ? coursesUnits[groupKey][subgroupKey].curr : 0;
+ const totalUOC = coursesUnits ? coursesUnits[groupKey][subgroupKey].total : 0;
+ if (subGroupEntry.length <= MAX_COURSES_OVERFLOW) defaultOpenKeys.push(subgroupKey);
+ return {
+ label: ,
+ key: subgroupKey,
+ disabled: !subGroupEntry.length, // disable submenu if there are no courses
+ // check if there are courses to show collapsible submenu
+ children: subGroupEntry.length
+ ? subGroupEntry
+ .sort(sortCourses)
+ .filter(
+ (course) =>
+ course.unlocked ||
+ courses[course.courseCode] !== undefined ||
+ showLockedCourses
+ )
+ .map((course) => ({
+ label: (
+
+ ),
+ // key is course code + groupKey + subgroupKey to differentiate as unique
+ // course items in menu
+ key: `${course.courseCode}-${groupKey}-${subgroupKey}`
+ }))
+ : null
+ };
+ })
+ }));
+ }
+ return [];
+ }, [
+ courses,
+ coursesUnits,
+ defaultOpenKeys,
+ menuData,
+ pageLoaded,
+ courseMutation.mutate,
+ showLockedCourses,
+ structureQuery.data,
+ structureQuery.isSuccess
+ ]);
const handleClick = ({ key }: { key: string }) => {
// course code is first 8 chars due to the key being course code + group + subGroup
diff --git a/frontend/src/pages/CourseSelector/CourseTabs/CourseTabs.tsx b/frontend/src/pages/CourseSelector/CourseTabs/CourseTabs.tsx
index 26ead0368..e3ba28a18 100644
--- a/frontend/src/pages/CourseSelector/CourseTabs/CourseTabs.tsx
+++ b/frontend/src/pages/CourseSelector/CourseTabs/CourseTabs.tsx
@@ -61,7 +61,7 @@ const CourseTabs = () => {
{...droppableProvided.droppableProps}
>
{tabs.map((tab, index) => (
-
+
))}
{droppableProvided.placeholder}
diff --git a/frontend/src/pages/DegreeWizard/YearStep/YearStep.tsx b/frontend/src/pages/DegreeWizard/YearStep/YearStep.tsx
index 4e98862b3..634e3027d 100644
--- a/frontend/src/pages/DegreeWizard/YearStep/YearStep.tsx
+++ b/frontend/src/pages/DegreeWizard/YearStep/YearStep.tsx
@@ -1,8 +1,6 @@
import React, { Suspense } from 'react';
import { animated, useSpring } from '@react-spring/web';
import { Typography } from 'antd';
-import dayjs from 'dayjs';
-import { RangeValue } from 'rc-picker/lib/interface';
import { DegreeWizardPayload } from 'types/degreeWizard';
import Spinner from 'components/Spinner';
import springProps from '../common/spring';
@@ -10,8 +8,8 @@ import Steps from '../common/steps';
import CS from '../common/styles';
const { Title } = Typography;
-const RangePicker = React.lazy(() =>
- import('components/Datepicker').then((d) => ({ default: d.default.RangePicker }))
+const YearPicker = React.lazy(() =>
+ import('antd').then((d) => ({ default: d.DatePicker.RangePicker }))
);
type SetState = React.Dispatch>;
@@ -24,10 +22,7 @@ type Props = {
const YearStep = ({ incrementStep, setDegreeInfo }: Props) => {
const props = useSpring(springProps);
- const handleOnChange = async (
- _: RangeValue,
- [startYear, endYear]: [string, string]
- ) => {
+ const handleOnChange = async (_: unknown, [startYear, endYear]: string | string[]) => {
// We can trust num years to be a valid number because the range picker only allows valid ranges
setDegreeInfo((prev) => ({
...prev,
@@ -45,9 +40,9 @@ const YearStep = ({ incrementStep, setDegreeInfo }: Props) => {
What years do you start and finish?
}>
-
- mapNodeStyle(c, courses[c]?.plannedFor, courses[c]?.unlocked, theme)
+ mapNodeStyle(c, !!courses[c]?.plannedFor, courses[c]?.unlocked, theme)
),
edges: programs.edges
};
@@ -253,7 +258,12 @@ const CourseGraph = ({
nodes?.map((n) =>
graphRef.current?.updateItem(
n,
- mapNodeStyle(n.getID(), courses[n.getID()].plannedFor, courses[n.getID()].unlocked, theme)
+ mapNodeStyle(
+ n.getID(),
+ !!courses[n.getID()]?.plannedFor,
+ courses[n.getID()]?.unlocked,
+ theme
+ )
)
);
diff --git a/frontend/src/pages/GraphicalSelector/CourseGraph/graph.ts b/frontend/src/pages/GraphicalSelector/CourseGraph/graph.ts
index 0816315db..6447b803b 100644
--- a/frontend/src/pages/GraphicalSelector/CourseGraph/graph.ts
+++ b/frontend/src/pages/GraphicalSelector/CourseGraph/graph.ts
@@ -87,7 +87,7 @@ const nodeLabelHoverStyle = (courseCode: string) => ({
...plannedLabel
});
-const nodeLabelUnhoverStyle = (courseCode: string, isPlanned: string | null, theme: string) => {
+const nodeLabelUnhoverStyle = (courseCode: string, isPlanned: boolean, theme: string) => {
if (isPlanned) {
return {
...sameNode(courseCode),
@@ -152,7 +152,7 @@ const edgeUnhoverStyle = (arrow: typeof Arrow, theme: string, id: string) => {
const mapNodeStyle = (
courseCode: string,
- isPlanned: string | null,
+ isPlanned: boolean,
isUnlocked: boolean,
theme: string
) => {
diff --git a/frontend/src/pages/LandingPage/FooterSection/Footer.tsx b/frontend/src/pages/LandingPage/FooterSection/Footer.tsx
index e112aa480..a41f94b6b 100644
--- a/frontend/src/pages/LandingPage/FooterSection/Footer.tsx
+++ b/frontend/src/pages/LandingPage/FooterSection/Footer.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import PageContainer from 'styles/PageContainer';
-import csesocLogoSrc from 'assets/csesocLogo.png';
+import devsocLogo from 'assets/devsocLogo.svg';
import footerBlobSrc from 'assets/LandingPage/footerBlob.svg';
import { CURR_YEAR } from 'config/constants';
import S from './styles';
@@ -13,13 +13,14 @@ const Footer = () => {
-
- © {CURR_YEAR} — CSESoc UNSW
+
+ © {CURR_YEAR} — UNSW Software Development Society
- CSESoc is the constituent student society of UNSW's School of Computer Science
- and Engineering. We do not represent the School, Faculty, or University.
+ Software Development Society (DevSoc) is a student society comprised of interested
+ developers, inventors and tech enthusiasts. We do not represent the School, Faculty,
+ or University (UNSW).
This website seeks to be a general guide for degree planning and course selection,
@@ -27,14 +28,13 @@ const Footer = () => {
correction. This is not official advice, and you should confirm any statements are
correct before relying on it. You should confirm with official resources endorsed by
UNSW and any information found here may not necessarily represent those of the
- University, Faculty, School, or the Computer Science and Engineering Society.
+ University, Faculty, School, or the Software Development Society.
- You are responsible for planning your degree and the Computer Science and
- Engineering Society have no responsibility on whether the information shown is
- accurate.
+ You are responsible for planning your degree and the Software Development Society
+ has no responsibility on whether the information shown is accurate.
- Circles was made with love by CSE students for CSE students.
+ Circles was made with love by students for students.
diff --git a/frontend/src/pages/LandingPage/FooterSection/styles.ts b/frontend/src/pages/LandingPage/FooterSection/styles.ts
index 422437e49..0b7a3ed6e 100644
--- a/frontend/src/pages/LandingPage/FooterSection/styles.ts
+++ b/frontend/src/pages/LandingPage/FooterSection/styles.ts
@@ -28,7 +28,7 @@ const FooterLogoWrapper = styled.div`
gap: 50px;
`;
-const CSELogo = styled.img`
+const DevSocLogo = styled.img`
width: 100%;
`;
@@ -45,5 +45,5 @@ export default {
FooterLogoWrapper,
FooterDisclaimer,
FooterWrapper,
- CSELogo
+ DevSocLogo
};
diff --git a/frontend/src/pages/LandingPage/Hero/HeroContent/HeroContent.tsx b/frontend/src/pages/LandingPage/Hero/HeroContent/HeroContent.tsx
index a1cc2550f..cf124b649 100644
--- a/frontend/src/pages/LandingPage/Hero/HeroContent/HeroContent.tsx
+++ b/frontend/src/pages/LandingPage/Hero/HeroContent/HeroContent.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { ArrowRightOutlined } from '@ant-design/icons';
import { Space } from 'antd';
-import cseLogo from 'assets/csesocLogo.png';
+import devsocLogo from 'assets/devsocLogo.svg';
import easySubTitle from 'assets/LandingPage/easySubtitle.svg';
import S from './styles';
@@ -22,9 +22,9 @@ const HeroContent = () => (
- (
<>
+
{inDev && }
diff --git a/frontend/src/pages/LandingPage/SponsorSection/SponsorSection.tsx b/frontend/src/pages/LandingPage/SponsorSection/SponsorSection.tsx
new file mode 100644
index 000000000..f715251c3
--- /dev/null
+++ b/frontend/src/pages/LandingPage/SponsorSection/SponsorSection.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import PageContainer from 'styles/PageContainer';
+import janestreetLogo from 'assets/LandingPage/janestreet.png';
+import tiktokLogo from 'assets/LandingPage/tiktok.svg';
+import S from './styles';
+
+type LogoProps = { src: string; href: string };
+
+const Logo = ({ src, href }: LogoProps) => (
+
+
+
+);
+
+const SponsorSection = () => (
+
+ Our sponsors
+
+
+
+
+
+);
+
+export default SponsorSection;
diff --git a/frontend/src/pages/LandingPage/SponsorSection/index.ts b/frontend/src/pages/LandingPage/SponsorSection/index.ts
new file mode 100644
index 000000000..799662a9a
--- /dev/null
+++ b/frontend/src/pages/LandingPage/SponsorSection/index.ts
@@ -0,0 +1,3 @@
+import SponsorSection from './SponsorSection';
+
+export default SponsorSection;
diff --git a/frontend/src/pages/LandingPage/SponsorSection/styles.ts b/frontend/src/pages/LandingPage/SponsorSection/styles.ts
new file mode 100644
index 000000000..2fe5bc0eb
--- /dev/null
+++ b/frontend/src/pages/LandingPage/SponsorSection/styles.ts
@@ -0,0 +1,28 @@
+import styled from 'styled-components';
+
+const SponsorsText = styled.h1`
+ font-size: 2rem;
+ background: -webkit-linear-gradient(30deg, #9f62de, #b77eff);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-align: center;
+ position: relative;
+ margin-bottom: 1rem;
+ font-weight: 650;
+`;
+
+const LogosWrapper = styled.div`
+ display: flex;
+ justify-content: center;
+ gap: 4rem;
+`;
+
+const LogoImg = styled.img`
+ height: 100px;
+`;
+
+export default {
+ SponsorsText,
+ LogosWrapper,
+ LogoImg
+};
diff --git a/frontend/src/pages/ProgressionChecker/Dashboard/Dashboard.tsx b/frontend/src/pages/ProgressionChecker/Dashboard/Dashboard.tsx
index 6e941968a..fa5022694 100644
--- a/frontend/src/pages/ProgressionChecker/Dashboard/Dashboard.tsx
+++ b/frontend/src/pages/ProgressionChecker/Dashboard/Dashboard.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useMemo } from 'react';
import { useQuery } from 'react-query';
import { scroller } from 'react-scroll';
import { ArrowDownOutlined } from '@ant-design/icons';
@@ -58,41 +58,43 @@ const Dashboard = ({ isLoading, structure, totalUOC, freeElectivesUOC }: Props)
}
});
- const storeUOC: StoreUOC = {};
-
// Example groups: Major, Minor, General, Rules
- Object.keys(structure).forEach((group) => {
- storeUOC[group] = {
- total: 0,
- curr: 0
- };
+ const storeUOC: StoreUOC = useMemo(() => {
+ const res: StoreUOC = {};
+ Object.keys(structure).forEach((group) => {
+ res[group] = {
+ total: 0,
+ curr: 0
+ };
- // Example subgroup: Core Courses, Computing Electives
- Object.keys(structure[group].content).forEach((subgroup) => {
- storeUOC[group].total += structure[group].content[subgroup].UOC;
- const subgroupStructure = structure[group].content[subgroup];
+ // Example subgroup: Core Courses, Computing Electives
+ Object.keys(structure[group].content).forEach((subgroup) => {
+ res[group].total += structure[group].content[subgroup].UOC;
+ const subgroupStructure = structure[group].content[subgroup];
- const isRule = subgroupStructure.type && subgroupStructure.type.includes('rule');
+ const isRule = subgroupStructure.type && subgroupStructure.type.includes('rule');
- if (subgroupStructure.courses && !isRule) {
- let currUOC = 0;
- // only consider disciplinary component courses
- Object.keys(subgroupStructure.courses).forEach((courseCode) => {
- if (
- courses[courseCode]?.plannedFor &&
- currUOC < subgroupStructure.UOC &&
- !courses[courseCode]?.ignoreFromProgression
- ) {
- const courseUOC =
- courses[courseCode].UOC *
- getNumTerms(courses[courseCode].UOC, courses[courseCode].isMultiterm);
- storeUOC[group].curr += courseUOC;
- currUOC += courseUOC;
- }
- });
- }
+ if (subgroupStructure.courses && !isRule) {
+ let currUOC = 0;
+ // only consider disciplinary component courses
+ Object.keys(subgroupStructure.courses).forEach((courseCode) => {
+ if (
+ courses[courseCode]?.plannedFor &&
+ currUOC < subgroupStructure.UOC &&
+ !courses[courseCode]?.ignoreFromProgression
+ ) {
+ const courseUOC =
+ courses[courseCode].UOC *
+ getNumTerms(courses[courseCode].UOC, courses[courseCode].isMultiterm);
+ res[group].curr += courseUOC;
+ currUOC += courseUOC;
+ }
+ });
+ }
+ });
});
- });
+ return res;
+ }, [courses, structure]);
const handleClick = () => {
scroller.scrollTo('divider', {
diff --git a/frontend/src/pages/TermPlanner/OptionsHeader/OptionsHeader.tsx b/frontend/src/pages/TermPlanner/OptionsHeader/OptionsHeader.tsx
index 1971913ce..af4634a45 100644
--- a/frontend/src/pages/TermPlanner/OptionsHeader/OptionsHeader.tsx
+++ b/frontend/src/pages/TermPlanner/OptionsHeader/OptionsHeader.tsx
@@ -3,22 +3,14 @@ import React from 'react';
import { FaRegCalendarTimes } from 'react-icons/fa';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { useDispatch, useSelector } from 'react-redux';
-import {
- DownloadOutlined,
- QuestionCircleOutlined,
- SettingFilled,
- UploadOutlined,
- WarningFilled
-} from '@ant-design/icons';
+import { QuestionCircleOutlined, SettingFilled, WarningFilled } from '@ant-design/icons';
import Tippy from '@tippyjs/react';
import { Popconfirm, Switch, Tooltip } from 'antd';
import { unscheduleAll } from 'utils/api/plannerApi';
import { getUserPlanner } from 'utils/api/userApi';
import type { RootState } from 'config/store';
import { toggleShowMarks, toggleShowWarnings } from 'reducers/settingsSlice';
-import ExportPlannerMenu from '../ExportPlannerMenu';
import HelpMenu from '../HelpMenu/HelpMenu';
-import ImportPlannerMenu from '../ImportPlannerMenu';
import SettingsMenu from '../SettingsMenu';
import { isPlannerEmpty } from '../utils';
import S from './styles';
@@ -26,11 +18,7 @@ import S from './styles';
import 'tippy.js/dist/tippy.css';
import 'tippy.js/themes/light.css';
-type Props = {
- plannerRef: React.RefObject;
-};
-
-const OptionsHeader = ({ plannerRef }: Props) => {
+const OptionsHeader = () => {
const queryClient = useQueryClient();
const plannerQuery = useQuery('planner', getUserPlanner);
@@ -79,7 +67,7 @@ const OptionsHeader = ({ plannerRef }: Props) => {
-