} action
+ */
+ deleteVisitedWebsite: (state, action) => {
+ const index = state.visitedWebsites.findIndex(visitedWebsite => visitedWebsite.id === action.payload);
+ if (index !== -1) {
+ state.visitedWebsites.splice(index, 1);
+ }
+ }
+ }
+});
+
+export const { setVisitedWebsite, addVisitedWebsite, updateVisitedWebsite, deleteVisitedWebsite } = visitedWebsiteSlice.actions;
+export default visitedWebsiteSlice.reducer;
diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js
new file mode 100644
index 000000000..5253d3ad9
--- /dev/null
+++ b/src/reportWebVitals.js
@@ -0,0 +1,13 @@
+const reportWebVitals = onPerfEntry => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
+};
+
+export default reportWebVitals;
diff --git a/src/router/layout.jsx b/src/router/layout.jsx
new file mode 100644
index 000000000..7500693f7
--- /dev/null
+++ b/src/router/layout.jsx
@@ -0,0 +1,13 @@
+import React from "react";
+import { Outlet } from "react-router-dom";
+import ResponsiveAppBar from "../stories/header/header";
+
+export default function Layout() {
+ return (
+ <>
+
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/router/router.jsx b/src/router/router.jsx
new file mode 100644
index 000000000..d195c813e
--- /dev/null
+++ b/src/router/router.jsx
@@ -0,0 +1,24 @@
+import React from "react";
+import {createBrowserRouter } from "react-router-dom";
+import ProfileList from "../components/profileComponent.jsx";
+import Layout from "./layout.jsx";
+export const router = createBrowserRouter([
+ {
+ path: '',
+ element: ,
+ children: [
+ {
+ path: '/',
+ element: home
+ },
+ {
+ path: '/home',
+ element: home
+ },
+ {
+ path: '/profiles',
+ element:
+ }
+ ]
+ },
+])
\ No newline at end of file
diff --git a/src/services/profileService.js b/src/services/profileService.js
new file mode 100644
index 000000000..482b4e321
--- /dev/null
+++ b/src/services/profileService.js
@@ -0,0 +1,56 @@
+import { handleGet, handlePost, handlePut, handleDelete } from '../axios/middleware.js'
+
+export const getAllProfiles = async () => {
+ try {
+ const response = await handleGet('/profiles');
+ return response.data;
+ } catch (err) {
+ console.error('Error getting all profiles:', err);
+ throw err;
+ }
+};
+export const createProfile = async (profileData) => {
+ try {
+ const response = await handlePost('/profiles', profileData);
+ return response.data;
+ } catch (err) {
+ console.error('Error creating profile:', err);
+ throw err;
+ }
+};
+export const getProfileById = async (id) => {
+ try {
+ const response = await handleGet(`/profiles/${id}`);
+ return response.data;
+ } catch (err) {
+ console.error(`Error getting profile with id ${id}:`, err);
+ throw err;
+ }
+};
+export const updateProfile = async (id, profileData) => {
+ try {
+ const response = await handlePut(`/profiles/${id}`, profileData);
+ return response.data;
+ } catch (err) {
+ console.error(`Error updating profile with id ${id}:`, err);
+ throw err;
+ }
+};
+export const getProfilesByUserId = async (userId) => {
+ try {
+ const response = await handleGet(`/profiles/user/${userId}`);
+ return response.data;
+ } catch (err) {
+ console.error(`Error getting profiles for user ${userId}:`, err);
+ throw err;
+ }
+};
+export const deleteProfile = async (id) => {
+ try {
+ const response = await handleDelete(`/profiles/${id}`);
+ return response.data;
+ } catch (err) {
+ console.error(`Error deleting profile with id ${id}:`, err);
+ throw err;
+ }
+};
\ No newline at end of file
diff --git a/src/services/userService.js b/src/services/userService.js
new file mode 100644
index 000000000..2a471b4d3
--- /dev/null
+++ b/src/services/userService.js
@@ -0,0 +1,12 @@
+import { handlePost } from '../axios/middleware';
+
+export const createUser = async (userData) => {
+ try {
+ console.log(userData,"userdata");
+ const response = await handlePost('/users', userData);
+ return response.data;
+ } catch (err) {
+ console.error('Error creating user:', err);
+ throw err;
+ }
+};
diff --git a/src/services/websiteService.js b/src/services/websiteService.js
new file mode 100644
index 000000000..dbe971615
--- /dev/null
+++ b/src/services/websiteService.js
@@ -0,0 +1,51 @@
+import { handleGet, handlePost, handlePut, handleDelete } from '../axios/middleware.js'
+
+export const getAllWebsites = async () => {
+ try {
+ const response = await handleGet('/websites');
+ return response.data;
+ } catch (err) {
+ console.error('Error getting all websites:', err);
+ throw err;
+ }
+};
+
+export const getWebsiteById = async (id) => {
+ try {
+ const response = await handleGet(`/websites/${id}`);
+ return response.data;
+ } catch (err) {
+ console.error(`Error getting website with id ${id}:`, err);
+ throw err;
+ }
+};
+
+export const createWebsite = async (websiteData) => {
+ try {
+ const response = await handlePost('/websites', websiteData);
+ return response.data;
+ } catch (err) {
+ console.error('Error creating website:', err);
+ throw err;
+ }
+};
+
+export const updateWebsite = async (id, websiteData) => {
+ try {
+ const response = await handlePut(`/websites/${id}`, websiteData);
+ return response.data;
+ } catch (err) {
+ console.error(`Error updating website with id ${id}:`, err);
+ throw err;
+ }
+};
+
+export const deleteWebsite = async (id) => {
+ try {
+ const response = await handleDelete(`/websites/${id}`);
+ return response.data;
+ } catch (err) {
+ console.error(`Error deleting website with id ${id}:`, err);
+ throw err;
+ }
+};
diff --git a/src/setupTests.js b/src/setupTests.js
new file mode 100644
index 000000000..8f2609b7b
--- /dev/null
+++ b/src/setupTests.js
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
diff --git a/src/stories/Button/GenericButton.css b/src/stories/Button/GenericButton.css
new file mode 100644
index 000000000..f86232a7b
--- /dev/null
+++ b/src/stories/Button/GenericButton.css
@@ -0,0 +1,18 @@
+@import url("https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap");
+.buttonWrapper .genericButton {
+ font-family: "Nanum Gothic", sans-serif;
+ font-optical-sizing: auto;
+ font-style: normal;
+ border-radius: 1em;
+ border: 2px;
+ border-style: solid;
+ border-color: rgb(103, 252, 210);
+}
+.buttonWrapper .genericButton.primary {
+ background-color: black;
+ color: white;
+}
+.buttonWrapper .genericButton.secondary {
+ background-color: white;
+ color: black;
+}/*# sourceMappingURL=GenericButton.css.map */
\ No newline at end of file
diff --git a/src/stories/Button/GenericButton.css.map b/src/stories/Button/GenericButton.css.map
new file mode 100644
index 000000000..d1b4d78cd
--- /dev/null
+++ b/src/stories/Button/GenericButton.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["GenericButton.scss","GenericButton.css"],"names":[],"mappings":"AAAQ,iFAAA;AAGJ;EACI,uCAAA;EACA,yBAAA;EACA,kBAAA;EACA,kBAAA;EACA,WAAA;EACA,mBAAA;EACA,gCAAA;ACDR;ADGQ;EACI,uBAAA;EACA,YAAA;ACDZ;ADIQ;EACI,uBAAA;EACA,YAAA;ACFZ","file":"GenericButton.css"}
\ No newline at end of file
diff --git a/src/stories/Button/GenericButton.jsx b/src/stories/Button/GenericButton.jsx
new file mode 100644
index 000000000..a76b8a35d
--- /dev/null
+++ b/src/stories/Button/GenericButton.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+
+import PropTypes from 'prop-types';
+
+import Button from '@mui/material/Button';
+
+import './GenericButton.scss';
+
+const GenericButton = ({className, label, onClick, size = "medium", disabled = false})=>{
+ return(
+
+
+
+ );
+};
+
+GenericButton.propTypes = {
+
+ className: PropTypes.string.isRequired,
+
+ //How large should the button be?
+ size: PropTypes.oneOf(['small', 'medium','large']),
+
+ //Button contents
+ label: PropTypes.string.isRequired,
+
+ //Click handler
+ onClick: PropTypes.func.isRequired,
+
+ //Optional is disabled
+ disabled: PropTypes.bool,
+};
+
+export default GenericButton;
\ No newline at end of file
diff --git a/src/stories/Button/GenericButton.scss b/src/stories/Button/GenericButton.scss
new file mode 100644
index 000000000..4cf767614
--- /dev/null
+++ b/src/stories/Button/GenericButton.scss
@@ -0,0 +1,26 @@
+@import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap');
+
+.buttonWrapper{
+ .genericButton{
+ font-family: "Nanum Gothic", sans-serif ;
+ font-optical-sizing: auto ;
+ font-style: normal ;
+ border-radius: 1em ;
+ border: 2px ;
+ border-style: solid ;
+ border-color: rgb(103, 252, 210) ;
+
+ &.primary{
+ background-color: black ;
+ color: white ;
+ }
+
+ &.secondary{
+ background-color: white;
+ color: black ;
+ }
+ }
+
+
+
+}
diff --git a/src/stories/Button/GenericButton.stories.js b/src/stories/Button/GenericButton.stories.js
new file mode 100644
index 000000000..c3e51e514
--- /dev/null
+++ b/src/stories/Button/GenericButton.stories.js
@@ -0,0 +1,31 @@
+import React from "react";
+import GenericButton from './GenericButton';
+
+
+export default{
+ title: 'Button/GenericButton',
+ component: GenericButton,
+ argTypes:{
+ className:{ control: {type: 'select', options:['primary','secondary']}},
+ }
+};
+
+
+// Button variations
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args ={
+ className:"primary",
+ label: "primary button",
+ size: "medium"
+};
+
+export const Secondary = Template.bind({});
+Secondary.args = {
+ className: "secondary",
+ label: "secondary button",
+ size: "medium"
+};
+
diff --git a/src/stories/GenericInput/constants.jsx b/src/stories/GenericInput/constants.jsx
new file mode 100644
index 000000000..355d2570e
--- /dev/null
+++ b/src/stories/GenericInput/constants.jsx
@@ -0,0 +1,2 @@
+
+export const INVALID_INPUT_MESSAGE = 'Invalid input';
diff --git a/src/stories/GenericInput/genericInput.jsx b/src/stories/GenericInput/genericInput.jsx
new file mode 100644
index 000000000..5043fcd35
--- /dev/null
+++ b/src/stories/GenericInput/genericInput.jsx
@@ -0,0 +1,84 @@
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+import { INVALID_INPUT_MESSAGE } from './constants';
+import { TextField, InputAdornment } from '@mui/material';
+import './genericInput.scss';
+const GenericInput = ({
+ label,
+ name,
+ type = 'text',
+ value = '',
+ onChange = () => {},
+ size = 'medium',
+ width = '20%',
+ icon: Icon = null,
+ disabled = false,
+ validation = () => {},
+ ...rest
+}) => {
+ const [inputValue, setInputValue] = useState(value);
+ const [error, setError] = useState(false);
+ const [helperText, setHelperText] = useState('');
+ useEffect(() => {
+ if (validation && typeof validation === 'function') {
+ handleValidation(inputValue);
+ }
+ }, [inputValue]);
+ const handleChange = (e) => {
+ const newValue = e.target.value;
+ setInputValue(newValue);
+ if (onChange) {
+ onChange({ target: { name, value: newValue } });
+ }
+ };
+ const handleValidation = (inputValue) => {
+ const validationResult = validation(inputValue);
+ if (validationResult && validationResult.error) {
+ setError(true);
+ setHelperText(validationResult.helperText || INVALID_INPUT_MESSAGE);
+ } else {
+ setError(false);
+ setHelperText('');
+ }
+ };
+ const inputStyle = {
+ width,
+ };
+ return (
+
+
+
+
+ ),
+ ...rest.InputProps,
+ }}
+ style={inputStyle}
+ {...rest}
+ />
+
+ );
+};
+GenericInput.propTypes = {
+ label: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+
+ type: PropTypes.oneOf(['text', 'number', 'email', 'password']),
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ onChange: PropTypes.func,
+ size: PropTypes.oneOf(['small', 'medium']),
+ width: PropTypes.string,
+ icon: PropTypes.elementType,
+ validation: PropTypes.func,
+};
+export default GenericInput;
\ No newline at end of file
diff --git a/src/stories/GenericInput/genericInput.scss b/src/stories/GenericInput/genericInput.scss
new file mode 100644
index 000000000..b2f198ea2
--- /dev/null
+++ b/src/stories/GenericInput/genericInput.scss
@@ -0,0 +1,79 @@
+@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap');
+@import './style.scss';
+
+.generic-input {
+ .MuiOutlinedInput-root {
+ border-radius: 8px;
+ transition: border-color 0.3s ease, box-shadow 0.3s ease;
+ border-color: $color-border;
+ border-width: 1px;
+ width: 50%;
+ margin-right: 200px;
+
+
+ &:hover {
+ border-color: $color-border-hover;
+ box-shadow: 0 0 5px rgba($color-border, 0.5);
+ }
+
+ &.Mui-focused fieldset {
+ border-color: $color-border-hover;
+ box-shadow: 0 0 8px rgba($color-border, 0.8);
+ }
+
+ &:not(.Mui-error) fieldset {
+ border-color: $color-border;
+ }
+
+ &.Mui-disabled {
+ opacity: 0.7;
+ cursor: not-allowed;
+
+ input {
+ color: rgba($color-black, 0.7);
+ pointer-events: none;
+ }
+ }
+
+ input {
+ color: $color-black;
+ font-family: 'Montserrat', sans-serif;
+ font-weight: 400;
+ font-size: 14px;
+ transition: color 0.3s ease;
+ text-align: left;
+ // margin-right: 200px;
+ // margin-bottom: 15px;
+ // height: 50px;
+ }
+
+ &.Mui-error {
+ border-color: $color-error;
+ }
+ }
+
+ .MuiFormLabel-root {
+ color: $color-black;
+ font-family: 'Montserrat', sans-serif;
+ font-weight: 400;
+ font-size: 16px;
+ transition: color 0.3s ease;
+
+
+ &.Mui-focused {
+ color: $color-border-hover;
+ }
+ }
+
+ .MuiFormHelperText-root {
+ color: $color-black;
+ font-family: 'Montserrat', sans-serif;
+ font-weight: 400;
+ font-size: 12px;
+ transition: color 0.3s ease;
+
+ &.Mui-error {
+ color: $color-error;
+ }
+ }
+}
diff --git a/src/stories/GenericInput/genericInput.stories.js b/src/stories/GenericInput/genericInput.stories.js
new file mode 100644
index 000000000..9e6f39a88
--- /dev/null
+++ b/src/stories/GenericInput/genericInput.stories.js
@@ -0,0 +1,85 @@
+import React from 'react';
+import GenericInput from '../inputs/genericInput';
+import PersonIcon from '@mui/icons-material/Person';
+
+export default {
+ title: 'Components/StyledInput',
+ component: GenericInput,
+ argTypes: {
+ size: {
+ control: {
+ type: 'select',
+ options: ['small', 'medium'],
+ },
+ },
+ width: {
+ control: 'text',
+ description: 'Width of the input, e.g. 100%, 50%, 300px'
+ },
+ },
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'Enter your details',
+ type: 'text',
+};
+
+export const InputWithPlaceholder = Template.bind({});
+InputWithPlaceholder.args = {
+ label: 'this is label',
+ type: 'text',
+ placeholder: 'This is Placeholder',
+};
+
+export const InputWithError = Template.bind({});
+InputWithError.args = {
+ label: 'Enter your details',
+ type: 'text',
+ helperText: 'Error message',
+ error: true,
+};
+
+export const EmailInput = Template.bind({});
+EmailInput.args = {
+ label: 'email input',
+ type: 'email',
+ placeholder: 'example@example.com',
+};
+
+export const InputWithIcon = Template.bind({});
+InputWithIcon.args = {
+ label: 'input with icon',
+ icon: PersonIcon,
+};
+
+export const NumberInput = Template.bind({});
+NumberInput.args = {
+ label: 'Choose number',
+ type: 'number',
+ size: 'small',
+};
+
+export const DisabledInput = Template.bind({});
+DisabledInput.args = {
+ label: 'Disabled Input',
+ type: 'text',
+ disabled: true,
+ width: '300px',
+};
+
+export const TimeInput = Template.bind({});
+TimeInput.args = {
+ label: '',
+ type: 'time',
+ size: 'medium',
+ width: '50%',
+};
+
+export const PasswordInput = Template.bind({});
+PasswordInput.args = {
+ label: 'Enter password',
+ type: 'password',
+};
diff --git a/src/stories/GenericInput/style.scss b/src/stories/GenericInput/style.scss
new file mode 100644
index 000000000..dd9b384e9
--- /dev/null
+++ b/src/stories/GenericInput/style.scss
@@ -0,0 +1,4 @@
+$color-border: rgb(61, 192, 155);
+$color-border-hover: rgb(45, 158, 126);
+$color-error: red;
+$color-black: black;
\ No newline at end of file
diff --git a/src/stories/RadioButton/radio-Button.jsx b/src/stories/RadioButton/radio-Button.jsx
new file mode 100644
index 000000000..ecc337a80
--- /dev/null
+++ b/src/stories/RadioButton/radio-Button.jsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Radio, FormControlLabel, RadioGroup, FormControl } from '@mui/material';
+import './radio-Button.scss';
+
+const RadioButtonComponent = ({ options, selectedOption, onChange }) => {
+ return (
+
+
+ {options.map(option => (
+ }
+ label={option.label}
+ className={`custom-form-control-label ${selectedOption === option.value ? 'Mui-checked' : ''}`}
+ labelPlacement="start"
+ />
+ ))}
+
+
+ );
+};
+
+RadioButtonComponent.propTypes = {
+ options: PropTypes.arrayOf(
+ PropTypes.shape({
+ value: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ })
+ ).isRequired,
+ selectedOption: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+};
+
+const RadioButton = React.memo(RadioButtonComponent);
+
+export default RadioButton;
diff --git a/src/stories/RadioButton/radio-Button.scss b/src/stories/RadioButton/radio-Button.scss
new file mode 100644
index 000000000..10852731c
--- /dev/null
+++ b/src/stories/RadioButton/radio-Button.scss
@@ -0,0 +1,46 @@
+@import '../variables.scss';
+
+.custom-radio-group {
+ padding: 5%;
+ color: $primary-color;
+}
+
+.custom-form-label,
+.custom-form-control-label {
+ font-family: 'Montserrat', sans-serif;
+ color: $primary-color;
+ margin-bottom: 4%;
+}
+
+.custom-form-label {
+ font-weight: 700;
+}
+
+.custom-form-control-label {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ cursor: pointer;
+
+ &.Mui-checked {
+ color: $secondary-color;
+ }
+}
+
+.custom-radio {
+ color: $primary-color;
+ transition: transform 0.2s ease;
+
+ &:hover {
+ transform: scale(1.05);
+ }
+
+ &.Mui-checked .MuiSvgIcon-root {
+ color: $secondary-color;
+ }
+
+
+ &.Mui-checked .MuiTouchRipple-root {
+ display: none;
+ }
+}
diff --git a/src/stories/RadioButton/radio-button.stories.js b/src/stories/RadioButton/radio-button.stories.js
new file mode 100644
index 000000000..b93e9510a
--- /dev/null
+++ b/src/stories/RadioButton/radio-button.stories.js
@@ -0,0 +1,50 @@
+import React, { useState } from 'react';
+
+import RadioButton from './radio-Button';
+
+export default {
+ title: 'Components/RadioButton',
+ component: RadioButton,
+ argTypes: {
+ options: { control: 'array' },
+ selectedOption: { control: 'text' },
+ onChange: { action: 'changed' },
+ },
+};
+
+const Template = (args) => {
+ const [selectedOption, setSelectedOption] = useState(args.selectedOption || '');
+
+ const handleChange = (event) => {
+ setSelectedOption(event.target.value);
+ args.onChange(event.target.value);
+ };
+
+ return (
+
+ );
+};
+
+export const Default = Template.bind({});
+Default.args = {
+ options: [
+ { value: 'option1', label: 'Option 1' },
+ { value: 'option2', label: 'Option 2' },
+ { value: 'option3', label: 'Option 3' },
+ ],
+ selectedOption: 'option1',
+};
+
+export const NoInitialSelection = Template.bind({});
+NoInitialSelection.args = {
+ options: [
+ { value: 'option1', label: 'Option 1' },
+ { value: 'option2', label: 'Option 2' },
+ { value: 'option3', label: 'Option 3' },
+ ],
+ selectedOption: '',
+};
diff --git a/src/stories/Select/Select.jsx b/src/stories/Select/Select.jsx
new file mode 100644
index 000000000..dd1fa4b3b
--- /dev/null
+++ b/src/stories/Select/Select.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import {Box,InputLabel,MenuItem,FormControl}from '@mui/material';
+import SelectMui from '@mui/material/Select';
+import PropTypes from 'prop-types';
+import { OPTION_SELSCT } from './select.constat';
+import './select.scss';
+
+const Select = ({
+ className,
+ options = OPTION_SELSCT,
+ onChange = () => {},
+ title,
+ size = 'large',
+ widthOfSelect
+}) => {
+ return (
+
+
+
+ {title}
+ onChange(event.target.value)}
+ >
+ {options.map((option, index) => (
+
+ ))}
+
+
+
+
+
+ );
+};
+
+Select.propTypes = {
+ options: PropTypes.arrayOf(PropTypes.shape({
+ value: PropTypes.any.isRequired,
+ text: PropTypes.string.isRequired,
+ iconSrc: PropTypes.string
+ })).isRequired,
+ title: PropTypes.string.isRequired,
+ onChange: PropTypes.func,
+ size: PropTypes.oneOf(['small', 'large']),
+ className: PropTypes.string.isRequired,
+ widthOfSelect: PropTypes.string
+};
+
+export default Select;
diff --git a/src/stories/Select/Select.stories.js b/src/stories/Select/Select.stories.js
new file mode 100644
index 000000000..966496908
--- /dev/null
+++ b/src/stories/Select/Select.stories.js
@@ -0,0 +1,47 @@
+import React from 'react';
+import Select from './Select';
+
+export default {
+ parameters: {
+ layout: 'centered',
+ },
+ title: 'Select/Select',
+ component: Select,
+ argTypes: {
+ className: { control: { type: 'select', options: ['primary', 'secondary'] } },
+ onChange: { action: 'changed' }, // This line is for Storybook actions addon
+ },
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ options: [
+ { value: 1, text: "option1", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' },
+ { value: 2, text: "option2", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' },
+ ],
+ className: "primary",
+ title: "primary select",
+ size: 'large',
+ widthOfSelect: "150px",
+ onChange: (selectedValue) => {
+ console.log('Selected value in Primary:', selectedValue);
+ },
+};
+
+export const Secondary = Template.bind({});
+Secondary.args = {
+ options: [
+ { value: 1, text: "option1", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' },
+ { value: 2, text: "option2", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' },
+ { value: 3, text: "option3", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' },
+ ],
+ className: "secondary",
+ title: "secondary select",
+ size: 'small',
+ widthOfSelect: "170px",
+ onChange: (selectedValue) => {
+ console.log('Selected value in Secondary:', selectedValue);
+ },
+};
diff --git a/src/stories/Select/select.constat.js b/src/stories/Select/select.constat.js
new file mode 100644
index 000000000..45afdec58
--- /dev/null
+++ b/src/stories/Select/select.constat.js
@@ -0,0 +1,4 @@
+export const OPTION_SELSCT = [
+ { value: 1, text: "Option 1", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' },
+ { value: 2, text: "Option 2", iconSrc: 'https://img.icons8.com/?size=100&id=Z13asb8sqRyN&format=png&color=000000' }
+ ];
\ No newline at end of file
diff --git a/src/stories/Select/select.scss b/src/stories/Select/select.scss
new file mode 100644
index 000000000..9bcb03f95
--- /dev/null
+++ b/src/stories/Select/select.scss
@@ -0,0 +1,54 @@
+@import '../variables.scss';
+.selectWrapper {
+ font-family: 'Nanum Gothic', sans-serif;
+
+ .genericSelect {
+ &.primary {
+ background-color: $background-class;
+ }
+
+ &.secondary {
+ background-color: $secondary-color;
+ }
+
+ &:hover .MuiOutlinedInput-notchedOutline {
+ border-color:$secondary-color;
+ }
+
+ &.Mui-focused .MuiOutlinedInput-notchedOutline {
+ border-color:$secondary-color;
+ }
+
+ .MuiOutlinedInput-notchedOutline {
+ border-width: 2px;
+ border-color:$secondary-color;
+
+ legend {
+ width: auto;
+ }
+ }
+
+ .MuiSelect-root {
+ font-family: 'Nanum Gothic', sans-serif;
+ }
+ }
+
+ .MuiInputLabel-root {
+ font-family: 'Nanum Gothic', sans-serif;
+
+ &.Mui-focused {
+ color:$primary-color;
+ }
+ }
+
+ .MuiMenuItem-root {
+ font-family: 'Nanum Gothic', sans-serif;
+
+
+ }
+}
+.img {
+ width: 23px;
+ height:23px;
+ margin-right: 3px;
+}
\ No newline at end of file
diff --git a/src/stories/Toast/ToastMessage.jsx b/src/stories/Toast/ToastMessage.jsx
new file mode 100644
index 000000000..e70e0c868
--- /dev/null
+++ b/src/stories/Toast/ToastMessage.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Alert, Snackbar } from '@mui/material';
+import './ToastMessage.scss';
+
+const ToastMessage = ({ open, type, message, onClose = () => {} }) => {
+ return (
+
+
+ {message}
+
+
+ );
+};
+
+ToastMessage.propTypes = {
+ open: PropTypes.bool.isRequired,
+ type: PropTypes.oneOf(['error', 'success', 'warning', 'info']).isRequired,
+ message: PropTypes.string.isRequired,
+ onClose: PropTypes.func,
+};
+
+export default ToastMessage;
diff --git a/src/stories/Toast/ToastMessage.scss b/src/stories/Toast/ToastMessage.scss
new file mode 100644
index 000000000..5f87734f7
--- /dev/null
+++ b/src/stories/Toast/ToastMessage.scss
@@ -0,0 +1,20 @@
+@import './variables.scss';
+.MuiAlert-root {
+ font-family: 'Montserrat', sans-serif;
+}
+
+.MuiSnackbar-root .MuiAlert-standardSuccess {
+ background-color: $standardSuccessColor;
+}
+
+.MuiSnackbar-root .MuiAlert-standardError {
+ background-color: $standardErrorColor;
+}
+
+.MuiSnackbar-root .MuiAlert-standardWarning {
+ background-color: $standardWarningColor;
+}
+
+.MuiSnackbar-root .MuiAlert-standardInfo {
+ background-color: $standardInfoColor;
+}
diff --git a/src/stories/Toast/ToastMessage.stories.js b/src/stories/Toast/ToastMessage.stories.js
new file mode 100644
index 000000000..16f6365a4
--- /dev/null
+++ b/src/stories/Toast/ToastMessage.stories.js
@@ -0,0 +1,55 @@
+import React, { useState } from 'react';
+import ToastMessage from './ToastMessage';
+
+export default {
+ title: 'Components/ToastMessage',
+ component: ToastMessage,
+ argTypes: {
+ type: {
+ control: { type: 'select', options: ['error', 'success', 'warning', 'info'] },
+ },
+ message: {
+ control: 'text',
+ },
+ open: {
+ control: 'boolean',
+ },
+
+ },
+};
+
+const Template = (args) => {
+ const [open, setOpen] = useState(args.open);
+
+
+
+ return ;
+};
+
+export const Success = Template.bind({});
+Success.args = {
+ open: true,
+ type: 'success',
+ message: 'This is a success message!',
+};
+
+export const Error = Template.bind({});
+Error.args = {
+ open: true,
+ type: 'error',
+ message: 'This is an error message!',
+};
+
+export const Warning = Template.bind({});
+Warning.args = {
+ open: true,
+ type: 'warning',
+ message: 'This is a warning message!',
+};
+
+export const Info = Template.bind({});
+Info.args = {
+ open: true,
+ type: 'info',
+ message: 'This is an info message!',
+};
diff --git a/src/stories/footer/FooterComponent.css b/src/stories/footer/FooterComponent.css
new file mode 100644
index 000000000..12cb247f3
--- /dev/null
+++ b/src/stories/footer/FooterComponent.css
@@ -0,0 +1,22 @@
+@import url("https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap");
+.footer-wrapper {
+ background-color: black;
+ color: rgb(103, 252, 210);
+ padding: 20px;
+ text-align: left;
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+}
+
+.footer-text {
+ font-size: 14px;
+ font-weight: 300;
+}
+
+.link-style {
+ color: rgb(103, 252, 210);
+ font-family: "Nanum Gothic", sans-serif;
+ font-optical-sizing: auto;
+ font-style: normal;
+}/*# sourceMappingURL=FooterComponent.css.map */
\ No newline at end of file
diff --git a/src/stories/footer/FooterComponent.css.map b/src/stories/footer/FooterComponent.css.map
new file mode 100644
index 000000000..007182870
--- /dev/null
+++ b/src/stories/footer/FooterComponent.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../variables.scss","FooterComponent.scss","FooterComponent.css"],"names":[],"mappings":"AAAQ,iFAAA;ACER;EACI,uBDDY;ECEZ,yBDDc;ECEd,aAAA;EACA,gBAAA;EACA,eAAA;EACA,SAAA;EACA,WAAA;ACAJ;;ADGE;EACE,eAAA;EACA,gBAAA;ACAJ;;ADEE;EACE,yBDdc;ECed,uCAAA;EACA,yBAAA;EACA,kBAAA;ACCJ","file":"FooterComponent.css"}
\ No newline at end of file
diff --git a/src/stories/footer/FooterComponent.jsx b/src/stories/footer/FooterComponent.jsx
new file mode 100644
index 000000000..1b14e8024
--- /dev/null
+++ b/src/stories/footer/FooterComponent.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { Box, Typography } from '@mui/material';
+import './FooterComponent.scss'
+
+const Footer = () => {
+ return (
+
+
+ © Developed by ExtraTech team.
+ visit us: ExtraTeck
+
+
+ );
+};
+
+export default Footer;
diff --git a/src/stories/footer/FooterComponent.scss b/src/stories/footer/FooterComponent.scss
new file mode 100644
index 000000000..8b3f49b47
--- /dev/null
+++ b/src/stories/footer/FooterComponent.scss
@@ -0,0 +1,22 @@
+@import '../variables.scss';
+
+.footer-wrapper {
+ background-color: $primary-color;
+ color: $secondary-color;
+ padding: 20px;
+ text-align: left;
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ }
+
+ .footer-text {
+ font-size: 14px;
+ font-weight: 300;
+ }
+ .link-style {
+ color: $secondary-color;
+ font-family: "Nanum Gothic", sans-serif;
+ font-optical-sizing: auto;
+ font-style: normal;
+ }
\ No newline at end of file
diff --git a/src/stories/genericInput.jsx b/src/stories/genericInput.jsx
new file mode 100644
index 000000000..278b1e33d
--- /dev/null
+++ b/src/stories/genericInput.jsx
@@ -0,0 +1,86 @@
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+import { TextField, InputAdornment } from '@mui/material';
+import '../style/genericInput.scss';
+
+const GenericInput = ({
+ label,
+ type = 'text',
+ value = '',
+ onChange = () => {},
+ size = 'medium',
+ width = '20%',
+ icon: Icon=null,
+ disabled= false,
+ validation = () => {},
+ ...rest
+}) => {
+ const [inputValue, setInputValue] = useState(value);
+ const [error, setError] = useState(false);
+ const [helperText, setHelperText] = useState('');
+
+ useEffect(() => {
+ if (validation && typeof validation === 'function') {
+ handleValidation(inputValue);
+ }
+ }, [inputValue]);
+
+ const handleChange = (e) => {
+ const newValue = e.target.value;
+ setInputValue(newValue);
+ onChange(newValue);
+ };
+
+ const handleValidation = (inputValue) => {
+ const validationResult = validation(inputValue);
+ if (validationResult && validationResult.error) {
+ setError(true);
+ setHelperText(validationResult.helperText || 'Invalid input');
+ } else {
+ setError(false);
+ setHelperText('');
+ }
+ };
+
+ const inputStyle = {
+ width,
+ };
+
+ return (
+
+
+
+
+ ),
+ ...rest.InputProps,
+ }}
+ style={inputStyle}
+ {...rest}
+ />
+
+ );
+};
+
+GenericInput.propTypes = {
+ label: PropTypes.string.isRequired,
+ type: PropTypes.oneOf(['text', 'number', 'email', 'password']),
+ value: PropTypes.string,
+ onChange: PropTypes.func,
+ size: PropTypes.oneOf(['small', 'medium']),
+ width: PropTypes.string,
+ icon: PropTypes.elementType,
+ validation: PropTypes.func,
+};
+
+export default GenericInput;
diff --git a/src/stories/genericInput.scss b/src/stories/genericInput.scss
new file mode 100644
index 000000000..2dcefb748
--- /dev/null
+++ b/src/stories/genericInput.scss
@@ -0,0 +1,78 @@
+@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap');
+
+$color-border: rgb(61, 192, 155);
+$color-border-hover: rgb(45, 158, 126);
+$color-error: red;
+$color-black: black;
+
+.generic-input {
+ .MuiOutlinedInput-root {
+ border-radius: 8px;
+ transition: border-color 0.3s ease, box-shadow 0.3s ease;
+ border-color: $color-border;
+ border-width: 1px;
+ width: 100%;
+
+ &:hover {
+ border-color: $color-border-hover;
+ box-shadow: 0 0 5px rgba($color-border, 0.5);
+ }
+
+ &.Mui-focused fieldset {
+ border-color: $color-border-hover;
+ box-shadow: 0 0 8px rgba($color-border, 0.8);
+ }
+
+ &:not(.Mui-error) fieldset {
+ border-color: $color-border;
+ }
+
+ &.Mui-disabled {
+ opacity: 0.7;
+ cursor: not-allowed;
+
+ input {
+ color: rgba($color-black, 0.7);
+ pointer-events: none;
+ }
+ }
+
+ input {
+ color: $color-black;
+ font-family: 'Montserrat', sans-serif;
+ font-weight: 400;
+ font-size: 14px;
+ transition: color 0.3s ease;
+ }
+
+ &.Mui-error {
+ border-color: $color-error;
+ }
+ }
+
+ .MuiFormLabel-root {
+ color: $color-black;
+ font-family: 'Montserrat', sans-serif;
+ font-weight: 400;
+ font-size: 16px;
+ transition: color 0.3s ease;
+
+ &.Mui-focused {
+ color: $color-border-hover;
+ }
+ }
+
+ .MuiFormHelperText-root {
+ color: $color-black;
+ font-family: 'Montserrat', sans-serif;
+ font-weight: 400;
+ font-size: 12px;
+ transition: color 0.3s ease;
+
+ &.Mui-error {
+ color: $color-error;
+ }
+ }
+}
+
+
diff --git a/src/stories/genericInput.stories.js b/src/stories/genericInput.stories.js
new file mode 100644
index 000000000..308b466c4
--- /dev/null
+++ b/src/stories/genericInput.stories.js
@@ -0,0 +1,91 @@
+
+import React from 'react';
+import GenericInput from '../inputs/genericInput';
+import PersonIcon from '@mui/icons-material/Person';
+
+export default {
+ title: 'Components/StyledInput',
+ component: GenericInput,
+ argTypes: {
+ size: {
+ control: {
+ type: 'select',
+ options: ['small', 'medium'],
+ },
+ width: {
+ control: 'text',
+ description: 'Width of the input, e.g. 100%, 50%, 300px'
+ },
+
+ },
+ },
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'Enter your details',
+ type: 'text',
+};
+
+export const InputWithPlaceholder = Template.bind({});
+InputWithPlaceholder.args = {
+ type: 'text',
+ label:'this is lable',
+ placeholder: 'This is Placeholder',
+};
+
+export const InputWithError = Template.bind({});
+InputWithError.args = {
+ label: 'Enter your details',
+ type: 'text',
+ helperText: 'Error message',
+ error: true,
+};
+
+export const EmailInput = Template.bind({});
+EmailInput.args = {
+ label:'email input',
+ type: 'email',
+ placeholder: 'example@example.com',
+
+};
+
+export const InputWithIcon = Template.bind({});
+InputWithIcon.args = {
+ label: 'input with icon',
+ icon:PersonIcon,
+};
+
+export const NumberInput = Template.bind({});
+NumberInput.args = {
+ label: 'Choose number',
+ type: 'number',
+ size: 'small',
+
+};
+
+export const DisabledInput = Template.bind({});
+DisabledInput.args = {
+ label: 'Disabled Input',
+ type: 'text',
+ disabled: true,
+ width:'300px',
+};
+
+export const TimeInput = Template.bind({});
+TimeInput.args = {
+ label:'',
+ type: 'time',
+ size:'medium',
+ width:'50%',
+};
+
+export const PasswordInput = Template.bind({});
+PasswordInput.args = {
+ label: 'Enter password',
+ type: 'password',
+
+};
+
diff --git a/src/stories/header/Header.stories.js b/src/stories/header/Header.stories.js
new file mode 100644
index 000000000..c5d9b78c7
--- /dev/null
+++ b/src/stories/header/Header.stories.js
@@ -0,0 +1,11 @@
+import * as React from 'react';
+import Header from './header';
+
+export default {
+ title:"header",
+ component:"Header"
+};
+
+const Template=()=>;
+
+export const clasicHeader=Template.bind({});
diff --git a/src/stories/header/header.css b/src/stories/header/header.css
new file mode 100644
index 000000000..5e2c0b3c1
--- /dev/null
+++ b/src/stories/header/header.css
@@ -0,0 +1,39 @@
+@import url("https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap");
+.navbar {
+ background-color: black;
+ color: rgb(103, 252, 210);
+}
+
+.logo {
+ margin-right: 2;
+ font-family: "Nanum Gothic";
+ color: rgb(103, 252, 210);
+ text-decoration: none;
+}
+
+.menu {
+ display: "block";
+ math-depth: "none";
+}
+
+.left-side-box {
+ flex-grow: 1;
+ display: flex;
+}
+@media (min-width: 768px) {
+ .left-side-box {
+ display: none;
+ }
+}
+
+.middle-side-box {
+ margin-left: 20vw;
+ flex-grow: 1;
+ display: none;
+}
+
+@media (min-width: 768px) {
+ .middle-side-box {
+ display: flex;
+ }
+}/*# sourceMappingURL=header.css.map */
\ No newline at end of file
diff --git a/src/stories/header/header.css.map b/src/stories/header/header.css.map
new file mode 100644
index 000000000..c5d7052a8
--- /dev/null
+++ b/src/stories/header/header.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../variables.scss","header.scss","header.css"],"names":[],"mappings":"AAGQ,iFAAA;ACDR;EACI,uBDFY;ECGZ,yBDFc;AEElB;;ADEA;EACI,eAAA;EACA,2BAAA;EACA,yBDPc;ECQd,qBAAA;ACCJ;;ADCA;EACK,gBAAA;EACA,kBAAA;ACEL;;ADAA;EACI,YAAA;EACA,aAAA;ACGJ;ADDI;EAJJ;IAKM,aAAA;ECIJ;AACF;;ADFA;EACI,iBAAA;EACE,YAAA;EACA,aAAA;ACKN;;ADFI;EACE;IACE,aAAA;ECKN;AACF","file":"header.css"}
\ No newline at end of file
diff --git a/src/stories/header/header.jsx b/src/stories/header/header.jsx
new file mode 100644
index 000000000..72e470d28
--- /dev/null
+++ b/src/stories/header/header.jsx
@@ -0,0 +1,118 @@
+import * as React from 'react';
+import { useState } from 'react';
+import {AppBar,Box,Toolbar,IconButton,Typography,Menu,AdbIcon,MenuItem,Tooltip,Button,Avatar,Container} from '@mui/material';
+import MenuIcon from '@mui/icons-material/Menu';
+import LabTabs from '../tabs/tabs';
+import './header.scss';
+function ResponsiveAppBar() {
+ const [currentname, setCurrentname] = useState(localStorage.getItem('nameUser') || null);
+ const [currentProfile, setCurrentProfile] = useState(localStorage.getItem('nameProfile') || null);
+
+ const [anchorElNav, setAnchorElNav] = useState(null);
+ const [anchorElUser, setAnchorElUser] = useState(null);
+ const handleOpenNavMenu = (event) => {
+ setAnchorElNav(event.currentTarget);
+ };
+ const handleOpenUserMenu = (event) => {
+ setAnchorElUser(event.currentTarget);
+ };
+ const handleCloseNavMenu = () => {
+ setAnchorElNav(null);
+ };
+ const handleCloseUserMenu = () => {
+ setAnchorElUser(null);
+ };
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ TimeOut
+
+
+
+
+
+
+ { !currentProfile && < IconButton onClick={handleOpenUserMenu} >
+
+ }
+
+ { currentProfile && < IconButton onClick={handleOpenUserMenu} >
+
+ }
+
+
+
+
+
+
+
+ );
+}
+export default ResponsiveAppBar;
\ No newline at end of file
diff --git a/src/stories/header/header.scss b/src/stories/header/header.scss
new file mode 100644
index 000000000..0cbaf297b
--- /dev/null
+++ b/src/stories/header/header.scss
@@ -0,0 +1,34 @@
+@import '../variables.scss';
+.arooundDiv{
+ .navbar{
+ background-color: $primary-color ;
+ color: $secondary-color ;
+ }
+ .logo{
+ margin-right: 2 ;
+ font-family: 'Nanum Gothic' ;
+ color: rgb(103, 252, 210) ;
+ text-decoration: none ;
+ }
+ .menu{
+ display: 'block' ;
+ math-depth: 'none' ;
+ }
+ .left-side-box{
+ flex-grow: 1;
+ display: flex;
+ @media (min-width: 768px) {
+ display: none;
+ }
+ }
+ .middle-side-box{
+ margin-left: 20vw;
+ flex-grow: 1;
+ display: none;
+ }
+ @media (min-width: 768px) {
+ .middle-side-box {
+ display: flex;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/stories/loader/loader.jsx b/src/stories/loader/loader.jsx
new file mode 100644
index 000000000..60b424dcc
--- /dev/null
+++ b/src/stories/loader/loader.jsx
@@ -0,0 +1,11 @@
+import React from 'react'
+import { CircularProgress } from '@mui/material'
+import './loader.scss'
+
+export default function Loader({className="primary"}) {
+ return (
+
+
+
+ )
+}
diff --git a/src/stories/loader/loader.scss b/src/stories/loader/loader.scss
new file mode 100644
index 000000000..c6e928ef4
--- /dev/null
+++ b/src/stories/loader/loader.scss
@@ -0,0 +1,10 @@
+@import '../variables.scss';
+
+.wrapDiv{
+ .secondary{
+ color: $secondary-color;
+ }
+ .primary{
+ color: $primary-color;
+ }
+}
\ No newline at end of file
diff --git a/src/stories/loader/loader.stories.js b/src/stories/loader/loader.stories.js
new file mode 100644
index 000000000..6ca067e73
--- /dev/null
+++ b/src/stories/loader/loader.stories.js
@@ -0,0 +1,25 @@
+
+import React from 'react';
+import PersonIcon from '@mui/icons-material/Person';
+import GenericInput from '../inputs/genericInput';
+import Loader from './loader';
+
+
+export default {
+ title: 'GenericLoad',
+ component: Loader,
+ }
+
+
+const Template = (args) => ;
+
+
+export const Primary = Template.bind({});
+Primary.args ={
+ className:"primary",
+}
+
+export const Secondary = Template.bind({});
+Secondary.args = {
+ className: "secondary",
+}
diff --git a/src/stories/stylies.css.map b/src/stories/stylies.css.map
new file mode 100644
index 000000000..cb38e2ead
--- /dev/null
+++ b/src/stories/stylies.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["stylies.scss"],"names":[],"mappings":"AAGQ,iFAAA","file":"stylies.css"}
\ No newline at end of file
diff --git a/src/stories/table/TableComponent.jsx b/src/stories/table/TableComponent.jsx
new file mode 100644
index 000000000..08d190333
--- /dev/null
+++ b/src/stories/table/TableComponent.jsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { DataGrid } from '@mui/x-data-grid';
+import PropTypes from 'prop-types'
+import './TableComponent.scss';
+
+const TableComponent = ({ dataObject, widthOfTable = "80%" ,widthOfColums}) => {
+ let columns = dataObject.headers.map((header,i) => ({
+ field: header,
+ headerName: header,
+ width: widthOfColums[i],
+ align:'center',
+ headerAlign: 'center'
+ }));
+
+ return (
+
+
+
+ );
+}
+
+TableComponent.propTypes = {
+ dataObject: PropTypes.shape({}).isRequired,
+ widthOfTable: PropTypes.string,
+ widthOfColums:PropTypes.arrayOf(PropTypes.number).isRequired
+};
+
+export default TableComponent;
+
diff --git a/src/stories/table/TableComponent.scss b/src/stories/table/TableComponent.scss
new file mode 100644
index 000000000..54f79cc38
--- /dev/null
+++ b/src/stories/table/TableComponent.scss
@@ -0,0 +1,81 @@
+@import '../variables.scss';
+
+.table {
+ background-color: $background-class;
+ margin-top: 10%;
+ border: 2px solid $primary-color;
+ text-align: center;
+ margin: auto;
+
+
+ .MuiDataGrid-row:hover,
+ .MuiDataGrid-cell:hover {
+ background-color: $secondary-color-hard;
+ border-color: $primary-color;
+ }
+
+ .MuiDataGrid-row:active,
+ .MuiDataGrid-cell:active {
+ background-color: $secondary-color-hard;
+ border-color: $secondary-color;
+ }
+
+ .MuiDataGrid-root {
+ border: none;
+ }
+
+ .MuiDataGrid-columnHeaders {
+ background-color: $primary-color;
+
+ .MuiDataGrid-columnHeaderTitle {
+ color: $secondary-color;
+ font-weight: bold;
+ text-align: center;
+ font-size: 140%;
+ font-family: "Nanum Gothic", sans-serif;
+ font-optical-sizing: auto;
+ font-style: normal;
+ }
+ }
+
+ .MuiDataGrid-cell {
+ color: $primary-color;
+ background-color: $background-class;
+ text-align: center;
+ font-size: 110%;
+
+ &:hover {
+ border-color: $secondary-color;
+ }
+ }
+
+ .MuiDataGrid-cellCheckbox,
+
+ .table.checkboxSelection{
+ .Mui-checked {
+ color: $secondary-color ;
+ }
+ }
+ .MuiDataGrid-footerContainer {
+ background-color: $background-class;
+
+ .MuiTablePagination-root {
+ color: $primary-color;
+ }
+ }
+
+ .MuiDataGrid-row {
+ &:hover {
+ background-color: $secondary-color-hard;
+ }
+
+ &.Mui-selected {
+ background-color: secondary-color-hard;
+
+ &:hover {
+ background-color: secondary-color-hard;
+ }
+ }
+ }
+}
+
diff --git a/src/stories/table/Tables.stories.js b/src/stories/table/Tables.stories.js
new file mode 100644
index 000000000..e11b6bbf2
--- /dev/null
+++ b/src/stories/table/Tables.stories.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import TableComponent from './TableComponent';
+
+const meta = {
+ title: 'TableComponent',
+ component: TableComponent,
+ argTypes: {
+ dataObject: { control: 'object' },
+ },
+};
+export default meta;
+
+const Template = (args) => ;
+export const data1 = Template.bind({});
+data1.args = {
+ dataObject: {
+ headers: ['id','name', 'age', 'city'],
+ rows: [
+ { id: 1, name: 'יונתן', age: 25, city: 'תל אביב' },
+ { id: 2, name: 'מיכל', age: 30, city: 'ירושלים' },
+ ],
+ },
+ widthOfTable:"60%",
+ widthOfColums:[150,150,150,150]
+};
+
+export const data2 = Template.bind({});
+data2.args = {
+ dataObject: {
+ headers: ['id','name', 'profession','age', 'city'],
+ rows: [
+ { id: 1, name: 'יונתן', profession: 'אנגלית', age: 25, city: 'תל אביב' },
+ { id: 2, name: 'מיכל', profession: 'חשבון', age: 30, city: 'ירושלים' },
+ ],
+ },
+ widthOfTable:"80%",
+ widthOfColums:[150,150,150,150,150]
+
+
+};
+
diff --git a/src/stories/tabs/tabs.css b/src/stories/tabs/tabs.css
new file mode 100644
index 000000000..98cdd6e80
--- /dev/null
+++ b/src/stories/tabs/tabs.css
@@ -0,0 +1,20 @@
+@import url("https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap");
+.div .every-tabs,
+.div .profile-tabs,
+.div .footer-tabs,
+.div .navbar-tabs {
+ background-color: black;
+ color: rgb(103, 252, 210);
+ font-family: "Nanum Gothic", sans-serif;
+ font-optical-sizing: auto;
+ font-style: normal;
+}
+.div .every-tabs.Mui-selected,
+.div .profile-tabs.Mui-selected,
+.div .footer-tabs.Mui-selected,
+.div .navbar-tabs.Mui-selected {
+ color: rgb(103, 252, 210);
+}
+.div .tabs {
+ background-color: rgb(103, 252, 210);
+}/*# sourceMappingURL=tabs.css.map */
\ No newline at end of file
diff --git a/src/stories/tabs/tabs.css.map b/src/stories/tabs/tabs.css.map
new file mode 100644
index 000000000..757e8b677
--- /dev/null
+++ b/src/stories/tabs/tabs.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../variables.scss","tabs.scss","tabs.css"],"names":[],"mappings":"AAGQ,iFAAA;ACAN;;;;EAIE,uBDNY;ECOZ,yBDNc;ECOd,uCAAA;EACA,yBAAA;EACA,kBAAA;ACDJ;ADEI;;;;EACE,yBDXY;AEclB;ADAE;EACE,oCDfc;AEiBlB","file":"tabs.css"}
\ No newline at end of file
diff --git a/src/stories/tabs/tabs.jsx b/src/stories/tabs/tabs.jsx
new file mode 100644
index 000000000..c35c0b5a4
--- /dev/null
+++ b/src/stories/tabs/tabs.jsx
@@ -0,0 +1,46 @@
+
+import * as React from 'react';
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import PropTypes from 'prop-types';
+import {Box,Tabs,Tab} from '@mui/material';
+import './tabs.scss'
+
+
+export default function LabTabs({ nameOfClass = "every-tabs", text = [], nav=[]}) {
+ const [value, setValue] = useState(0);
+
+ const handleChange = (event, newValue) => {
+ setValue(newValue);
+ };
+
+ const navigate = useNavigate();
+
+ const handleTabClick = (index) => {
+ if (nav && nav[index]) {
+ navigate(nav[index]);
+ }
+ };
+
+ return (
+
+
+
+ {Array.isArray(text) && text.map((label, index) => (
+ handleTabClick(index)}/>
+ ))}
+
+
+
+ );
+}
+
+LabTabs.propTypes = {
+ text: PropTypes.arrayOf(PropTypes.string).isRequired,
+ nameOfClass: PropTypes.string,
+ nav:PropTypes.arrayOf(PropTypes.string).isRequired
+};
+
diff --git a/src/stories/tabs/tabs.scss b/src/stories/tabs/tabs.scss
new file mode 100644
index 000000000..9dc339726
--- /dev/null
+++ b/src/stories/tabs/tabs.scss
@@ -0,0 +1,20 @@
+@import '../variables.scss';
+
+.div {
+ .every-tabs,
+ .profile-tabs,
+ .footer-tabs,
+ .navbar-tabs {
+ background-color: $primary-color;
+ color: $secondary-color;
+ font-family: "Nanum Gothic", sans-serif;
+ font-optical-sizing: auto;
+ font-style: normal;
+ &.Mui-selected {
+ color: $secondary-color;
+ }
+ }
+ .tabs {
+ background-color: $secondary-color;
+ }
+}
diff --git a/src/stories/tabs/tabs.stories.js b/src/stories/tabs/tabs.stories.js
new file mode 100644
index 000000000..4c367637a
--- /dev/null
+++ b/src/stories/tabs/tabs.stories.js
@@ -0,0 +1,35 @@
+import * as React from 'react';
+import LabTabs from './tabs';
+
+export default {
+ title:"tab",
+ component:"LabTabs",
+};
+
+const Template=(args)=>;
+
+export const navbarTabs=Template.bind({});
+navbarTabs.args={
+ nameOfClass:"navbar-tabs",
+ text:["home","reports","statistics","profiles"],
+ nav:["/home","/reports","/statistics","/profiles"],
+};
+
+export const widthtabs=Template.bind({});
+widthtabs.args={
+ classNameOfTags:"width-tabs",
+};
+
+export const footerTabs=Template.bind({});
+footerTabs.args={
+ nameOfClass:"footer-tabs",
+ text:["Extratech"],
+ nav:["https://ultracode.education/"],
+};
+
+export const profileTabs=Template.bind({});
+profileTabs.args={
+ nameOfClass:"profile-tabs",
+ text:["blocked sites","manage profiles","browsing data"],
+ nav:["/blockedsites","/manageprofiles","/browsingdata"]
+};
diff --git a/src/stories/variables.css b/src/stories/variables.css
new file mode 100644
index 000000000..37b2016d7
--- /dev/null
+++ b/src/stories/variables.css
@@ -0,0 +1 @@
+@import url("https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap");/*# sourceMappingURL=variables.css.map */
\ No newline at end of file
diff --git a/src/stories/variables.css.map b/src/stories/variables.css.map
new file mode 100644
index 000000000..d2dab4ddc
--- /dev/null
+++ b/src/stories/variables.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["variables.scss"],"names":[],"mappings":"AAAQ,iFAAA","file":"variables.css"}
\ No newline at end of file
diff --git a/src/stories/variables.scss b/src/stories/variables.scss
new file mode 100644
index 000000000..f3c0f75ad
--- /dev/null
+++ b/src/stories/variables.scss
@@ -0,0 +1,8 @@
+
+$standardSuccessColor:rgba(229, 245, 233, 0.8);
+$standardErrorColor:rgba(254, 226, 226, 0.8);
+$standardWarningColor:rgba(255, 255, 224, 0.8);
+$standardInfoColor:rgba(224, 242, 241, 0.8);
+$primary-color: black;
+$secondary-color: rgb(103, 252, 210);
+@import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap');
diff --git a/src/types/types.js b/src/types/types.js
new file mode 100644
index 000000000..ceef6a5b6
--- /dev/null
+++ b/src/types/types.js
@@ -0,0 +1,77 @@
+/**
+ * @typedef {Object} Website
+ * @property {string} id
+ * @property {string} name
+ * @property {string} url
+ */
+
+/**
+ * @typedef {Object} VisitTime
+ * @property {Date} visitDate
+ * @property {number} activityTime
+ */
+
+/**
+ * @typedef {Object} VisitedWebsite
+ * @property {string|Website} website
+ * @property {VisitTime[]} visitsTime
+ */
+
+/**
+ * @typedef {Object} VisitedWebsites
+ * @property {string} id
+ * @property {VisitedWebsite[]} visitedWebsites
+ */
+
+/**
+ * @typedef {Object} User
+ * @property {string} id
+ * @property {string} name
+ * @property {string} email
+ * @property {string} [password]
+ * @property {string} [googleId]
+ * @property {(string|VisitedWebsite)[]} visitsWebsites
+ * @property {string[]} profiles
+ * @property {string[]} preferences
+ * @property {string} [profileImage]
+ */
+
+/**
+ * @typedef {Object} ListWebsite
+ * @property {string|Website} websiteId
+ * @property {'block' | 'open' | 'limit'} status
+ * @property {number} limitedMinutes
+ */
+
+/**
+ * @typedef {Object} Profile
+ * @property {string} id
+ * @property {string|User} userId
+ * @property {string} profileName
+ * @property {'black list' | 'white list'} [statusBlockedSites]
+ * @property {ListWebsite[]} listWebsites
+ * @property {{start: Date, end: Date}} timeProfile
+ */
+
+/**
+ * @typedef {Object} Preference
+ * @property {string} id
+ * @property {'never' | 'daily' | 'weekly' | 'monthly' | 'yearly'} emailFrequency
+ * @property {number} sendNotificationTime
+ * @property {string} [soundVoice]
+ */
+
+/**
+ * @typedef {Object} AuthUser
+ * @property {string} [token]
+ * @property {User} user
+ */
+
+
+/**
+ * @typedef {ReturnType} RootState
+ */
+
+/**
+ * @type {import('react-redux').TypedUseSelectorHook}
+ */
\ No newline at end of file