@@ -38,18 +49,21 @@ export const LadderDetails = ({ ladder, ladderName, band }: LadderDetailsProps)
))}
- {ladder.softSkillBuckets.length > 0 && (
+ {/* TODO: replace with:
+ ladder.softSkillBuckets.length > 0
+ */}
+ {softSkills.length > 0 && (
Soft skills
- {ladder.softSkillBuckets.map((bucket: LadderBandBucket) => (
+ {softSkills.map((bucket: LadderBandBucket) => (
))}
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.hooks.ts b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.hooks.ts
new file mode 100644
index 00000000..1ecdaceb
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.hooks.ts
@@ -0,0 +1,14 @@
+import { useState } from 'react';
+
+export const useMySpaceBucketDetails = () => {
+ const [levelOpen, setLevelOpen] = useState
(null);
+
+ const handleOpen = (level: null | number) => {
+ setLevelOpen((prev) => (prev === level ? null : level));
+ };
+
+ return {
+ levelOpen,
+ handleOpen,
+ };
+};
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.interface.ts b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.interface.ts
new file mode 100644
index 00000000..333e90b0
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.interface.ts
@@ -0,0 +1,5 @@
+import { Bucket } from '@app/types/library';
+
+export interface MySpaceBucketDetailsProps {
+ data: Bucket;
+}
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.tsx b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.tsx
new file mode 100644
index 00000000..c860086b
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/MySpaceBucketDetails.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { MySpaceBucketDetailsProps } from './MySpaceBucketDetails.interface';
+import { routes } from '@app/constants';
+import { Breadcrumbs } from '@app/components/modules/Breadcrumbs';
+import { Typography } from '@app/components/common/Typography';
+import { AdvancementLevel } from './modules/AdvancementLevel';
+import { useMySpaceBucketDetails } from './MySpaceBucketDetails.hooks';
+import { LevelDots } from '@app/components/modules/LevelDots';
+
+export const MySpaceBucketDetails: React.FC = ({ data }) => {
+ const { bucketSlug, bucketName, description, advancementLevels } = data;
+ const { levelOpen, handleOpen } = useMySpaceBucketDetails();
+ const level = 2;
+
+ return (
+
+
+
+
+
+
+
+ {bucketName}
+
+
+
+ Level {level}
+
+
+
+
+
+ {description}
+
+
+
+
+ {advancementLevels.map((level, index) => (
+
handleOpen(level.advancementLevel)}
+ />
+ ))}
+
+
+
+ );
+};
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/index.ts b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/index.ts
new file mode 100644
index 00000000..b1dcd60b
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/index.ts
@@ -0,0 +1 @@
+export { MySpaceBucketDetails } from './MySpaceBucketDetails';
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.hooks.ts b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.hooks.ts
new file mode 100644
index 00000000..e2a24bcc
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.hooks.ts
@@ -0,0 +1,14 @@
+import { useState } from 'react';
+
+export const useAdvancementLevel = () => {
+ const [modalOpen, setModalOpen] = useState(false);
+
+ const openModal = () => setModalOpen(true);
+ const hideModal = () => setModalOpen(false);
+
+ return {
+ hideModal,
+ openModal,
+ modalOpen,
+ };
+};
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.interface.ts b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.interface.ts
new file mode 100644
index 00000000..55e4b68d
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.interface.ts
@@ -0,0 +1,8 @@
+import { AdvancementLevel } from '@app/types/library';
+
+export interface AdvancementLevelProps {
+ data: AdvancementLevel;
+ verticalLine: boolean;
+ open: boolean;
+ onClick: () => void;
+}
diff --git a/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.tsx b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.tsx
new file mode 100644
index 00000000..e3551621
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/AdvancementLevel.tsx
@@ -0,0 +1,54 @@
+'use client';
+import { AccordionCard } from '@app/components/common/AccordionCard';
+import { AccordionList } from '@app/components/common/AccordionList';
+import { AdvancementLevelProps } from './AdvancementLevel.interface';
+import { Button } from '@app/components/common/Button';
+import { ExpandableSection } from '@app/components/common/ExpandableSection';
+import { ExampleWayToPassLevelModal } from '@app/components/modules/ExampleWayToPassLevelModal';
+import { useAdvancementLevel } from './AdvancementLevel.hooks';
+import { SkillStatusIcon } from '@app/components/modules/SkillStatusIcon';
+
+export const AdvancementLevel: React.FC = ({ verticalLine, data, open, onClick }) => {
+ const { hideModal, openModal, modalOpen } = useAdvancementLevel();
+ const { advancementLevel, description, projects, categories } = data;
+ const shouldBeExpandedByDefault = Object.keys(data.categories).length === 1;
+
+ return (
+
+ <>
+ {projects.length > 0 && (
+ <>
+
+
+ >
+ )}
+ {Object.entries(categories).map(([category, skills]) => (
+
+ ({
+ key: name,
+ title: name,
+ children: description ? {description}
: undefined,
+ icon: ,
+ }))}
+ />
+
+ ))}
+ >
+
+ );
+};
diff --git a/frontend/src/components/modules/AdvancementLevel/index.ts b/frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/index.ts
similarity index 100%
rename from frontend/src/components/modules/AdvancementLevel/index.ts
rename to frontend/src/components/pages/mySpace/MySpaceBucketDetails/modules/AdvancementLevel/index.ts
diff --git a/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/MySpaceSoftSkillBucketDetails.interface.ts b/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/MySpaceSoftSkillBucketDetails.interface.ts
new file mode 100644
index 00000000..e0a37ef5
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/MySpaceSoftSkillBucketDetails.interface.ts
@@ -0,0 +1,5 @@
+import { SoftSkillBucket } from '@app/types/library';
+
+export interface MySpaceSoftSkillBucketDetailsProps {
+ data: SoftSkillBucket;
+}
diff --git a/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/MySpaceSoftSkillBucketDetails.tsx b/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/MySpaceSoftSkillBucketDetails.tsx
new file mode 100644
index 00000000..18a0eb6b
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/MySpaceSoftSkillBucketDetails.tsx
@@ -0,0 +1,52 @@
+'use client';
+
+import { routes } from '@app/constants';
+import { Breadcrumbs } from '@app/components/modules/Breadcrumbs';
+import { Typography } from '@app/components/common/Typography';
+import { MySpaceSoftSkillBucketDetailsProps } from './MySpaceSoftSkillBucketDetails.interface';
+import { StatusChip } from '@app/components/common/StatusChip';
+import { AccordionCard } from '@app/components/common/AccordionCard';
+import { AccordionList } from '@app/components/common/AccordionList';
+import { SkillStatusIcon } from '@app/components/modules/SkillStatusIcon';
+
+export const MySpaceSoftSkillBucketDetails: React.FC = ({ data }) => {
+ const { description, status, categories } = data;
+
+ return (
+
+
+
+
+
+
+
+ Soft skills
+
+ {status}
+
+
+ {description}
+
+ {Object.entries(categories).map(([category, skills]) => (
+
+ ({
+ key: name,
+ title: name,
+ children: description ? {description}
: undefined,
+ icon: ,
+ }))}
+ />
+
+ ))}
+
+
+
+
+ );
+};
diff --git a/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/index.ts b/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/index.ts
new file mode 100644
index 00000000..b503e4c0
--- /dev/null
+++ b/frontend/src/components/pages/mySpace/MySpaceSoftSkillBucketDetails/index.ts
@@ -0,0 +1 @@
+export { MySpaceSoftSkillBucketDetails } from './MySpaceSoftSkillBucketDetails';
diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts
index b8802b33..ba887844 100644
--- a/frontend/src/constants/routes.ts
+++ b/frontend/src/constants/routes.ts
@@ -7,6 +7,7 @@ export const routes = {
},
mySpace: {
index: '/my-space',
+ softSkills: '/my-space/soft-skills',
},
people: {
index: '/people?tab=active&page=1',
diff --git a/frontend/src/static/icons/ArrowRight.tsx b/frontend/src/static/icons/ArrowRight.tsx
new file mode 100644
index 00000000..f72cbe65
--- /dev/null
+++ b/frontend/src/static/icons/ArrowRight.tsx
@@ -0,0 +1,11 @@
+export const ArrowRight: React.FC> = (props) => (
+
+);
diff --git a/frontend/src/static/icons/CrossIcon.tsx b/frontend/src/static/icons/CrossIcon.tsx
new file mode 100644
index 00000000..d18cacb5
--- /dev/null
+++ b/frontend/src/static/icons/CrossIcon.tsx
@@ -0,0 +1,10 @@
+export const CrossIcon: React.FC> = (props) => (
+
+);
diff --git a/frontend/src/static/icons/DashedCircle.tsx b/frontend/src/static/icons/DashedCircle.tsx
new file mode 100644
index 00000000..b83734a5
--- /dev/null
+++ b/frontend/src/static/icons/DashedCircle.tsx
@@ -0,0 +1,15 @@
+export const DashedCircle: React.FC> = (props) => (
+
+);
diff --git a/frontend/src/types/library.ts b/frontend/src/types/library.ts
index fb94376d..9a54a714 100644
--- a/frontend/src/types/library.ts
+++ b/frontend/src/types/library.ts
@@ -8,22 +8,33 @@ export interface LadderBand {
export interface LadderBandBucket {
bucketName: string;
bucketSlug: string;
- bucketType: typeof BucketType;
+ bucketType: keyof typeof BucketType;
description: string;
level?: number;
+ status?: string;
}
export interface Bucket {
bucketName: string;
bucketSlug: string;
- bucketType: typeof BucketType;
+ bucketType: keyof typeof BucketType;
description: string;
advancementLevels: AdvancementLevel[];
}
+export interface SoftSkillBucket {
+ bucketName: string;
+ bucketSlug: string;
+ description: string;
+ status?: string;
+ categories: {
+ [categoryGroup: string]: AtomicSkill[];
+ };
+}
+
export const BucketType = {
- HARD: 'hard',
- SOFT: 'soft',
+ hard: 'hard',
+ soft: 'soft',
} as const;
export interface AdvancementLevel {
@@ -43,4 +54,16 @@ export interface ExampleProject {
export interface AtomicSkill {
name: string;
description?: string;
+ proofStatus?: keyof typeof ProofStatus;
}
+
+export const ProofStatus = {
+ approved: 'approved',
+ pending: 'pending',
+ rejected: 'rejected',
+} as const;
+
+export const SoftSkillStatus = {
+ completed: 'completed',
+ pending: 'pending',
+} as const;