;
+
+export const Primary: Story = {
+ args: {
+ isOpen: true,
+ onClose: () => {},
+ title: "Modal Title",
+ children: This is the modal content.
,
+ size: 'lg',
+
+ },
+};
\ No newline at end of file
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal/Modal.tsx
similarity index 96%
rename from src/components/ui/Modal.tsx
rename to src/components/ui/Modal/Modal.tsx
index f29df68..5e9952b 100644
--- a/src/components/ui/Modal.tsx
+++ b/src/components/ui/Modal/Modal.tsx
@@ -9,6 +9,9 @@ interface ModalProps {
size?: 'sm' | 'md' | 'lg' | 'xl';
}
+/**
+ * A reusable modal component with customizable size and close functionality.
+ */
export default function Modal({ isOpen, onClose, title, children, size = 'lg' }: ModalProps) {
const modalRef = useRef(null);
diff --git a/src/components/ui/ProfileField/ProfileField.stories.tsx b/src/components/ui/ProfileField/ProfileField.stories.tsx
new file mode 100644
index 0000000..f4b4f39
--- /dev/null
+++ b/src/components/ui/ProfileField/ProfileField.stories.tsx
@@ -0,0 +1,20 @@
+import type { Meta, StoryObj } from '@storybook/react-vite';
+
+import ProfileField from './ProfileField';
+
+const meta = {
+ component: ProfileField,
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ isEditing: false,
+ label: "User Name",
+ value: "",
+ icon: 👤,
+
+ },
+};
\ No newline at end of file
diff --git a/src/components/ui/ProfileField.tsx b/src/components/ui/ProfileField/ProfileField.tsx
similarity index 76%
rename from src/components/ui/ProfileField.tsx
rename to src/components/ui/ProfileField/ProfileField.tsx
index eee0454..f32eb43 100644
--- a/src/components/ui/ProfileField.tsx
+++ b/src/components/ui/ProfileField/ProfileField.tsx
@@ -1,11 +1,16 @@
import React from 'react';
-import Input, { type InputProps } from './Input/Input';
+import Input, { type InputProps } from '../Input/Input';
interface ProfileFieldProps extends InputProps {
isEditing: boolean;
icon: React.ReactNode;
}
+/**
+ * A component that displays a profile field which can be either in view mode or edit mode.
+ *
+ * @param {ProfileFieldProps} props - The properties to configure the ProfileField component.
+ */
const ProfileField = React.forwardRef(
({ isEditing, icon, label, value, ...props }, ref) => {
if (isEditing) {
diff --git a/src/components/ui/RoleBadge/RoleBadge.stories.tsx b/src/components/ui/RoleBadge/RoleBadge.stories.tsx
new file mode 100644
index 0000000..fc10f10
--- /dev/null
+++ b/src/components/ui/RoleBadge/RoleBadge.stories.tsx
@@ -0,0 +1,28 @@
+import type { Meta, StoryObj } from '@storybook/react-vite';
+import RoleBadge from './RoleBadge';
+
+const meta = {
+ component: RoleBadge,
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Professor: Story = {
+ args: {
+ role: 'professor',
+ },
+};
+
+export const Student: Story = {
+ args: {
+ role: 'student',
+ },
+};
+
+export const Admin: Story = {
+ args: {
+ role: 'admin',
+ },
+};
+
diff --git a/src/components/ui/RoleBadge.tsx b/src/components/ui/RoleBadge/RoleBadge.tsx
similarity index 83%
rename from src/components/ui/RoleBadge.tsx
rename to src/components/ui/RoleBadge/RoleBadge.tsx
index 08d9d0d..9466296 100644
--- a/src/components/ui/RoleBadge.tsx
+++ b/src/components/ui/RoleBadge/RoleBadge.tsx
@@ -1,11 +1,14 @@
-import Badge from './Badge/Badge';
+import Badge from '../Badge/Badge';
import { Shield, GraduationCap } from 'lucide-react';
-import type { UserRole } from '../../types/entities';
+import type { UserRole } from '../../../types/entities';
interface RoleBadgeProps {
role: UserRole;
}
+/**
+ * RoleBadge component to display user roles with specific styles and icons.
+ */
const RoleBadge = ({ role }: RoleBadgeProps) => {
switch (role) {
case 'admin':
diff --git a/src/components/ui/Select/Select.stories.tsx b/src/components/ui/Select/Select.stories.tsx
new file mode 100644
index 0000000..d2407d4
--- /dev/null
+++ b/src/components/ui/Select/Select.stories.tsx
@@ -0,0 +1,22 @@
+import type { Meta, StoryObj } from '@storybook/react-vite';
+
+import Select from './Select';
+
+const meta = {
+ component: Select,
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ id: 'example-select',
+ label: 'Example Select',
+ children: (<>
+
+
+
+ >),
+ },
+};
\ No newline at end of file
diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select/Select.tsx
similarity index 97%
rename from src/components/ui/Select.tsx
rename to src/components/ui/Select/Select.tsx
index 523c77d..fbbd7a6 100644
--- a/src/components/ui/Select.tsx
+++ b/src/components/ui/Select/Select.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { cn } from '../../lib/utils';
+import { cn } from '../../../lib/utils';
/**
* Props for the Select component.
diff --git a/src/components/ui/Switch.tsx b/src/components/ui/Swtich/Switch.tsx
similarity index 95%
rename from src/components/ui/Switch.tsx
rename to src/components/ui/Swtich/Switch.tsx
index 2c36d05..f7c1a1e 100644
--- a/src/components/ui/Switch.tsx
+++ b/src/components/ui/Swtich/Switch.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { cn } from '../../lib/utils';
+import { cn } from '../../../lib/utils';
type SwitchProps = React.InputHTMLAttributes;
diff --git a/src/components/ui/Swtich/Swtich.stories.tsx b/src/components/ui/Swtich/Swtich.stories.tsx
new file mode 100644
index 0000000..ef4b2b5
--- /dev/null
+++ b/src/components/ui/Swtich/Swtich.stories.tsx
@@ -0,0 +1,17 @@
+import type { Meta, StoryObj } from '@storybook/react-vite';
+
+import Switch from './Switch';
+
+const meta = {
+ component: Switch,
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ id: 'example-switch',
+ checked: false
+ },
+};
\ No newline at end of file
diff --git a/src/pages/Admin/ProfessorAppealsPage.tsx b/src/pages/Admin/ProfessorAppealsPage.tsx
index ba80cee..3d25841 100644
--- a/src/pages/Admin/ProfessorAppealsPage.tsx
+++ b/src/pages/Admin/ProfessorAppealsPage.tsx
@@ -9,7 +9,7 @@ import {
} from '../../components/ui/Card';
import { Dialog, DialogHeader, DialogTitle } from '../../components/ui/Dialog';
import StatusBadge from '../../components/ui/StatusBadge/StatusBadge';
-import DocumentViewer from '../../components/ui/DocumentViewer';
+import DocumentViewer from '../../components/ui/DocumentViewer/DocumentViewer.tsx';
import {
Check,
X,
diff --git a/src/pages/Course/CourseListPage.tsx b/src/pages/Course/CourseListPage.tsx
index b9d7b34..9474b3b 100644
--- a/src/pages/Course/CourseListPage.tsx
+++ b/src/pages/Course/CourseListPage.tsx
@@ -1,15 +1,15 @@
import { useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import CardList from '../../components/ui/CardList/CardList.tsx';
-import CoursePreviewCard from '../../components/ui/CoursePreviewCard.tsx';
+import CoursePreviewCard from '../../components/ui/CoursePreviewCard/CoursePreviewCard.tsx';
import type { SearchCoursesParams } from '../../types/shared.ts';
import { useSearchCourses } from '../../hooks/useCourses.ts';
import { useCourseTypes } from '../../hooks/useCourseTypes.ts';
import { useInstitutions } from '../../hooks/useInstitutionMutations.ts';
import Input from '../../components/ui/Input/Input.tsx';
-import Select from '../../components/ui/Select.tsx';
-import Switch from '../../components/ui/Switch.tsx';
-import Label from '../../components/ui/Label.tsx';
+import Select from '../../components/ui/Select/Select.tsx';
+import Switch from '../../components/ui/Swtich/Switch.tsx';
+import Label from '../../components/ui/Label/Label.tsx';
import Button from '../../components/ui/Button/Button.tsx';
import { Search, LayoutGrid, List } from 'lucide-react';
import { useDebounce } from '../../hooks/useDebounce.ts';
diff --git a/src/pages/Professor/ProfessorAppeal.tsx b/src/pages/Professor/ProfessorAppeal.tsx
index 2bb353b..b32a0a0 100644
--- a/src/pages/Professor/ProfessorAppeal.tsx
+++ b/src/pages/Professor/ProfessorAppeal.tsx
@@ -7,7 +7,7 @@ import Button from "../../components/ui/Button/Button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../../components/ui/Card"
import Input from "../../components/ui/Input/Input"
import Textarea from "../../components/ui/TextArea/TextArea"
-import Label from "../../components/ui/Label"
+import Label from "../../components/ui/Label/Label"
import { BookOpen, ArrowLeft, GraduationCap, Upload } from "lucide-react"
import { useCreateAppeal } from '../../hooks/useCreateAppeal'
import { useMyAppeals } from "../../hooks/useAppeals"
diff --git a/src/pages/Professor/ProfessorAppealStatusPage.tsx b/src/pages/Professor/ProfessorAppealStatusPage.tsx
index b1c388c..b1ea43b 100644
--- a/src/pages/Professor/ProfessorAppealStatusPage.tsx
+++ b/src/pages/Professor/ProfessorAppealStatusPage.tsx
@@ -5,7 +5,7 @@ import { Card } from '../../components/ui/Card';
import StatusBadge from '../../components/ui/StatusBadge/StatusBadge';
import Button from '../../components/ui/Button/Button';
import { Dialog, DialogHeader, DialogTitle } from '../../components/ui/Dialog';
-import DocumentViewer from '../../components/ui/DocumentViewer';
+import DocumentViewer from '../../components/ui/DocumentViewer/DocumentViewer';
import { ArrowLeft, Calendar, Eye, GraduationCap, ExternalLink, Info } from 'lucide-react';
import type { Appeal } from '../../types/entities';
diff --git a/src/pages/Professor/ProfessorAssessmentEditor.tsx b/src/pages/Professor/ProfessorAssessmentEditor.tsx
index 1f3dca9..6aa8efa 100644
--- a/src/pages/Professor/ProfessorAssessmentEditor.tsx
+++ b/src/pages/Professor/ProfessorAssessmentEditor.tsx
@@ -10,9 +10,9 @@ import Button from '../../components/ui/Button/Button';
import { Card } from '../../components/ui/Card';
import Input from '../../components/ui/Input/Input';
import TextArea from '../../components/ui/TextArea/TextArea';
-import Select from '../../components/ui/Select';
-import Switch from '../../components/ui/Switch';
-import Label from '../../components/ui/Label';
+import Select from '../../components/ui/Select/Select';
+import Switch from '../../components/ui/Swtich/Switch';
+import Label from '../../components/ui/Label/Label';
import QuestionSelector from '../../components/professor/assessments/QuestionSelector';
import { ArrowLeft, Save, Plus, Trash2 } from 'lucide-react';
import type {
diff --git a/src/pages/Professor/ProfessorAssessmentsPage.tsx b/src/pages/Professor/ProfessorAssessmentsPage.tsx
index 45992d4..458cda8 100644
--- a/src/pages/Professor/ProfessorAssessmentsPage.tsx
+++ b/src/pages/Professor/ProfessorAssessmentsPage.tsx
@@ -7,7 +7,7 @@ import {
} from '../../hooks/useAssessments';
import Button from '../../components/ui/Button/Button';
import { Card } from '../../components/ui/Card';
-import Select from '../../components/ui/Select';
+import Select from '../../components/ui/Select/Select';
import {
Clock,
FileText,
diff --git a/src/pages/Professor/ProfessorCourseCreation.tsx b/src/pages/Professor/ProfessorCourseCreation.tsx
index eb18c27..eb2d219 100644
--- a/src/pages/Professor/ProfessorCourseCreation.tsx
+++ b/src/pages/Professor/ProfessorCourseCreation.tsx
@@ -6,10 +6,10 @@ import Button from "../../components/ui/Button/Button.tsx";
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/Card.tsx";
import Input from "../../components/ui/Input/Input.tsx";
import Textarea from "../../components/ui/TextArea/TextArea.tsx";
-import CoursePreviewCard from "../../components/ui/CoursePreviewCard.tsx";
-import Switch from "../../components/ui/Switch.tsx";
-import Label from "../../components/ui/Label.tsx";
-import Select from "../../components/ui/Select.tsx";
+import CoursePreviewCard from "../../components/ui/CoursePreviewCard/CoursePreviewCard.tsx";
+import Switch from "../../components/ui/Swtich/Switch.tsx";
+import Label from "../../components/ui/Label/Label.tsx";
+import Select from "../../components/ui/Select/Select.tsx";
import { useCourseTypes } from "../../hooks/useCourseTypes.ts";
import { useCreateCourse } from "../../hooks/useCourses.ts";
import * as v from 'valibot';
diff --git a/src/pages/Professor/ProfessorCoursesPage.tsx b/src/pages/Professor/ProfessorCoursesPage.tsx
index a7af910..65e2fba 100644
--- a/src/pages/Professor/ProfessorCoursesPage.tsx
+++ b/src/pages/Professor/ProfessorCoursesPage.tsx
@@ -3,7 +3,7 @@ import Button from '../../components/ui/Button/Button';
import Badge from '../../components/ui/Badge/Badge.tsx';
import { Edit, Plus, Star } from 'lucide-react';
import { useProfessorCourses } from '../../hooks/useCourses.ts';
-import CoursePreviewCard from '../../components/ui/CoursePreviewCard';
+import CoursePreviewCard from '../../components/ui/CoursePreviewCard/CoursePreviewCard.tsx';
const ProfessorCoursesPage = () => {
const { data: courses, isLoading, error } = useProfessorCourses();
diff --git a/src/pages/User/ProfilePage.tsx b/src/pages/User/ProfilePage.tsx
index fe76f36..0b7c065 100644
--- a/src/pages/User/ProfilePage.tsx
+++ b/src/pages/User/ProfilePage.tsx
@@ -11,7 +11,7 @@ import {
CardTitle,
} from "../../components/ui/Card";
import Button from "../../components/ui/Button/Button";
-import ProfileField from "../../components/ui/ProfileField";
+import ProfileField from "../../components/ui/ProfileField/ProfileField";
import {
Tabs,
TabsContent,
@@ -40,7 +40,7 @@ import {
import { useAuth } from "../../hooks/useAuth";
import { useUpdateProfile } from "../../hooks/useUserMutations";
import { isAxiosError } from "axios";
-import RoleBadge from "../../components/ui/RoleBadge";
+import RoleBadge from "../../components/ui/RoleBadge/RoleBadge";
import ProfessorProfileTab from "./ProfessorProfileTab";
import StudentAppealsHistory from "../../components/student/StudentAppealsHistory";