diff --git a/.env b/.env
deleted file mode 100644
index 970babe..0000000
--- a/.env
+++ /dev/null
@@ -1,3 +0,0 @@
-BASE_URL=http://localhost:4455
-NEXTAUTH_SECRET=SOME_SECRET
-NEXTAUTH_URL=http://localhost:3000
diff --git a/public/images/avatar.jpg b/public/images/avatar.jpg
deleted file mode 100644
index 19ba5b8..0000000
Binary files a/public/images/avatar.jpg and /dev/null differ
diff --git a/public/svgs/organisation-default.svg b/public/svgs/organisation-default.svg
new file mode 100644
index 0000000..60939e3
--- /dev/null
+++ b/public/svgs/organisation-default.svg
@@ -0,0 +1,30 @@
+
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 4c9aaf1..0773bc1 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -13,7 +13,11 @@ export const metadata: Metadata = {
description: 'Generated by create next app',
};
-export default function RootLayout({ children }: { children: ReactNode }) {
+export default async function RootLayout({
+ children,
+}: {
+ children: ReactNode;
+}) {
return (
diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx
index f95d955..c0feb5a 100644
--- a/src/app/not-found.tsx
+++ b/src/app/not-found.tsx
@@ -6,12 +6,6 @@ import Image from 'next/image';
import { useRouter } from 'next/navigation';
import Button from '@/components/common/ui/button';
-import {
- ButtonColor,
- ButtonIcon,
- ButtonSize,
- ButtonVariant,
-} from '@/components/common/ui/button/types';
import * as styles from '../components/pages/NotFound.styles';
@@ -30,13 +24,7 @@ const NotFound: FC = () => {
Ви можете написати в підтримку, якщо ви впевнені, що виникла помилка
-
+
-
-
+
+
);
}
return (
-
- {mocks.map((organisation) => (
-
- ))}
-
- Створити
-
-
+
+
+ {mocks.map((organisation) => (
+
+
+
+ ))}
+
+ Створити
+
+
+
);
};
diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx
index 2de64c9..06bdb10 100644
--- a/src/app/profile/page.tsx
+++ b/src/app/profile/page.tsx
@@ -7,7 +7,7 @@ import ProfileHeader from '@/app/profile/components/profile-header';
import Tabs from './components/tabs';
import * as styles from './ProfilePage.styles';
-const Profile = () => {
+const Profile = async () => {
return (
diff --git a/src/app/test/button/page.tsx b/src/app/test/button/page.tsx
index f070c09..cc5142a 100644
--- a/src/app/test/button/page.tsx
+++ b/src/app/test/button/page.tsx
@@ -114,6 +114,12 @@ const ButtonPage = () => {
Button
+
+ Button
+ {' '}
+
+ Button
+
diff --git a/src/app/test/icon-button/page.tsx b/src/app/test/icon-button/page.tsx
new file mode 100644
index 0000000..198f014
--- /dev/null
+++ b/src/app/test/icon-button/page.tsx
@@ -0,0 +1,18 @@
+import { Box } from '@mui/material';
+
+import IconButton from '@/components/common/ui/icon-button/IconButton';
+
+const Page = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Page;
diff --git a/src/app/test/organisation-card/page.tsx b/src/app/test/organisation-card/page.tsx
index 7ac26fb..791e88d 100644
--- a/src/app/test/organisation-card/page.tsx
+++ b/src/app/test/organisation-card/page.tsx
@@ -1,6 +1,9 @@
import { Stack, Typography } from '@mui/material';
-import OrganisationCard from '@/components/common/ui/organisation-card';
+import { Card, Position, Price } from '@/components/common/ui/card/Card';
+import Auto from '@/components/common/ui/card/components/Auto';
+import Phone from '@/components/common/ui/card/components/Phone';
+import type { Auto as IAuto } from '@/types/auto';
const mocks = [
{
@@ -24,18 +27,64 @@ const mocks = [
},
];
+const autoMocks: IAuto[] = [
+ {
+ id: 1,
+ number: 'ABC123',
+ brand: 'Toyota',
+ model: 'Corolla',
+ year: 2020,
+ vin: '1HGBH41JXMN109186',
+ engine: '1.8L',
+ volume: 1800,
+ },
+ {
+ id: 2,
+ number: 'XYZ789',
+ brand: 'Honda',
+ model: 'Civic',
+ year: 2018,
+ vin: '2HGBH41JXMN109187',
+ engine: '2.0L',
+ volume: 2000,
+ },
+ {
+ id: 3,
+ number: 'DEF456',
+ brand: 'Ford',
+ model: 'Focus',
+ year: 2019,
+ vin: '3HGBH41JXMN109188',
+ engine: '1.5L',
+ volume: 1500,
+ },
+];
+
const Page = () => {
return (
Organisation Card
{mocks.map((mock, index) => (
-
+ >
+
+
+ ))}
+
+
+
+
+
+
+
+ {autoMocks.map((auto: IAuto) => (
+
+
+
))}
);
diff --git a/src/components/common/layout/page-layout/footer/Footer.styles.ts b/src/components/common/layout/page-layout/footer/Footer.styles.ts
index 5a9537b..3c4e62f 100644
--- a/src/components/common/layout/page-layout/footer/Footer.styles.ts
+++ b/src/components/common/layout/page-layout/footer/Footer.styles.ts
@@ -10,14 +10,11 @@ export const wrapper: SxProps = {
desktop: 'flex-start',
mobile: 'center',
},
- justifyContent: {
- desktop: 'space-between',
- mobile: 'center',
- },
- zIndex: 11,
+ zIndex: 10,
padding: {
- mobileMedium: '38px 100px',
+ desktop: '38px 100px',
+ mobileMedium: '38px 50px',
mobile: '16px',
},
height: 'auto',
@@ -41,7 +38,13 @@ export const text: SxProps = {
};
export const columns: SxProps = {
+ width: '100%',
display: 'flex',
+ justifyContent: {
+ desktop: 'flex-end',
+ mobileMedium: 'center',
+ mobile: 'space-between',
+ },
gap: {
desktop: '80px',
mobileMedium: '40px',
diff --git a/src/components/common/layout/page-layout/footer/constants/index.ts b/src/components/common/layout/page-layout/footer/constants/index.ts
index 0d91d13..97444e6 100644
--- a/src/components/common/layout/page-layout/footer/constants/index.ts
+++ b/src/components/common/layout/page-layout/footer/constants/index.ts
@@ -8,8 +8,8 @@ export const links: Links = {
href: '/',
},
{
- title: 'Організація',
- href: '/organization',
+ title: 'Організації',
+ href: '/organizations',
},
{
title: 'Ціни',
diff --git a/src/components/common/layout/page-layout/header/Header.styles.ts b/src/components/common/layout/page-layout/header/Header.styles.ts
index 50475a2..b175d7a 100644
--- a/src/components/common/layout/page-layout/header/Header.styles.ts
+++ b/src/components/common/layout/page-layout/header/Header.styles.ts
@@ -1,7 +1,12 @@
import { SxProps, Theme } from '@mui/material/styles';
export const wrapper: SxProps = {
- p: '0px 100px',
+ py: 0,
+ px: {
+ mobile: '16px',
+ tablet: '32px',
+ desktop: '100px',
+ },
width: '100%',
height: '64px',
boxShadow: 'rgba(0, 0, 0, 0.24) 0px 3px 8px',
diff --git a/src/components/common/layout/page-layout/header/menu/constants/menuItems.ts b/src/components/common/layout/page-layout/header/menu/constants/menuItems.ts
index 8a613f1..959786f 100644
--- a/src/components/common/layout/page-layout/header/menu/constants/menuItems.ts
+++ b/src/components/common/layout/page-layout/header/menu/constants/menuItems.ts
@@ -4,8 +4,8 @@ export const menuItems = [
url: '/',
},
{
- title: 'Організація',
- url: '/organisation',
+ title: 'Організації',
+ url: '/organisations',
},
{
title: 'Ціни',
diff --git a/src/components/common/ui/button/Button.styles.ts b/src/components/common/ui/button/Button.styles.ts
index a9160fa..fd20dd6 100644
--- a/src/components/common/ui/button/Button.styles.ts
+++ b/src/components/common/ui/button/Button.styles.ts
@@ -73,6 +73,27 @@ const outlinedWhiteColors: SxProps = {
},
};
+const textColors: SxProps = {
+ backgroundColor: 'transparent',
+ borderColor: 'transparent',
+ color: 'black.main',
+ '&:hover': {
+ backgroundColor: 'rgba(255, 84, 30, 0.15);',
+ borderColor: 'transparent',
+ },
+ '&:active': {
+ backgroundColor: 'rgba(255, 84, 30, 0.35)',
+ color: 'orange.100',
+ },
+ '&:focus': {
+ backgroundColor: 'rgba(255, 84, 30, 0.15)',
+ borderColor: 'orange.300',
+ },
+ '&.Mui-disabled': {
+ color: 'gray.500',
+ },
+};
+
export const button = (
variant: ButtonVariant,
size: ButtonSize,
@@ -85,23 +106,25 @@ export const button = (
borderRadius: '6px',
textTransform: 'none',
display: 'flex',
+
+ ...(size === 'small' && {
+ typography: 'body1Bold',
+ p: '10px 20px',
+ gap: '8px',
+ }),
+ ...(size === 'medium' && {
+ p: '12px 28px',
+ typography: 'h6Bold',
+ gap: '12px',
+ }),
+ ...(size === 'large' && {
+ p: '16px 32px',
+ gap: '12px',
+ typography: 'h6Bold',
+ }),
+
...(variant === 'contained' && {
...containedColors,
- ...(size === 'small' && {
- typography: 'body1Bold',
- p: '10px 20px',
- gap: '8px',
- }),
- ...(size === 'medium' && {
- p: '12px 28px',
- typography: 'h6Bold',
- gap: '12px',
- }),
- ...(size === 'large' && {
- p: '16px 32px',
- gap: '12px',
- typography: 'h6Bold',
- }),
}),
...(variant === 'outlined' && {
...(color === 'primary' && {
@@ -110,20 +133,11 @@ export const button = (
...(color === 'secondary' && {
...outlinedWhiteColors,
}),
- ...(size === 'small' && {
- typography: 'body1Bold',
- p: '10px 20px',
- gap: '8px',
- }),
- ...(size === 'medium' && {
- p: '12px 28px',
- typography: 'h6Bold',
- gap: '12px',
- }),
- ...(size === 'large' && {
- p: '16px 32px',
- gap: '12px',
- typography: 'h6Bold',
- }),
+ }),
+ ...(variant === 'text' && {
+ p: '10px 24px',
+ border: '1px solid',
+ typography: 'body1Medium',
+ ...textColors,
}),
});
diff --git a/src/components/common/ui/button/Button.tsx b/src/components/common/ui/button/Button.tsx
index 7b90ff1..d6ed4b9 100644
--- a/src/components/common/ui/button/Button.tsx
+++ b/src/components/common/ui/button/Button.tsx
@@ -27,7 +27,11 @@ const Button: FC = ({
...rest
}) => {
return (
-
+
{icon === 'left' && iconComponent}
{children}
{icon === 'right' && iconComponent}
diff --git a/src/components/common/ui/button/types/index.ts b/src/components/common/ui/button/types/index.ts
index d9f08a1..c7cc625 100644
--- a/src/components/common/ui/button/types/index.ts
+++ b/src/components/common/ui/button/types/index.ts
@@ -2,6 +2,6 @@ export type ButtonSize = 'small' | 'medium' | 'large';
export type ButtonIcon = 'none' | 'left' | 'right';
-export type ButtonVariant = 'contained' | 'outlined';
+export type ButtonVariant = 'contained' | 'outlined' | 'text';
export type ButtonColor = 'primary' | 'secondary';
diff --git a/src/components/common/ui/card/Card.styles.ts b/src/components/common/ui/card/Card.styles.ts
new file mode 100644
index 0000000..fe816b9
--- /dev/null
+++ b/src/components/common/ui/card/Card.styles.ts
@@ -0,0 +1,107 @@
+import { SxProps, Theme } from '@mui/material/styles';
+
+const defaultTextSettings = {
+ typography: 'body1',
+ color: 'black',
+};
+
+export const wrapper: SxProps = {
+ width: '100%',
+
+ display: 'block',
+ borderRadius: '6px',
+ border: '1px solid',
+ borderColor: 'gray.500',
+ backgroundColor: 'gray.700',
+ boxShadow: '2px 2px 4px 0px rgba(0, 0, 0, 0.25)',
+
+ '&:hover': {
+ backgroundColor: 'gray.600',
+ },
+
+ '&:focus': {
+ outline: '2px solid',
+ outlineColor: 'gray.100',
+ },
+};
+
+export const box: SxProps = {
+ flex: '1 1 auto',
+ height: 'auto',
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+};
+
+export const content: SxProps = {
+ p: {
+ mobile: '12px 0 12px 20px',
+ },
+};
+
+export const title: SxProps = {
+ display: 'flex',
+ justifyContent: 'space-between',
+};
+
+export const info: SxProps = {
+ display: 'grid',
+ gridTemplateColumns: 'auto 1fr',
+ columnGap: '20px',
+};
+
+export const heading: SxProps = {
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'flex-start',
+ gap: '8px',
+};
+
+export const avatar: SxProps = {
+ width: '64px',
+ height: '64px',
+ border: '1px solid',
+ borderColor: 'gray.500',
+};
+
+export const price: SxProps = {
+ typography: 'body1Bold',
+ color: 'orange.100',
+};
+
+export const phone: SxProps = defaultTextSettings;
+export const auto: SxProps = defaultTextSettings;
+
+export const description: SxProps = {
+ mt: '14px',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ display: '-webkit-box',
+ WebkitLineClamp: 3,
+ WebkitBoxOrient: 'vertical',
+};
+
+export const button: SxProps = {
+ alignSelf: 'stretch',
+ width: {
+ mobile: '28px',
+ tablet: '44px',
+ },
+ height: {
+ mobile: 'auto',
+ tablet: '44px',
+ },
+ borderRadius: {
+ tablet: '50%',
+ mobile: '0 6px 6px 0',
+ },
+ m: {
+ mobile: 0,
+ tablet: '22px 16px 0 0',
+ },
+ p: {
+ mobile: '4px',
+ tablet: 0,
+ },
+};
diff --git a/src/components/common/ui/card/Card.tsx b/src/components/common/ui/card/Card.tsx
new file mode 100644
index 0000000..b83fa06
--- /dev/null
+++ b/src/components/common/ui/card/Card.tsx
@@ -0,0 +1,56 @@
+'use client';
+import { FC } from 'react';
+import { Avatar, Box, Typography } from '@mui/material';
+import Link from 'next/link';
+
+import Position from '@/components/common/ui/card/components/Position';
+import Price from '@/components/common/ui/card/components/Price';
+import RoundButtonIcon from '@/components/common/ui/round-button-icon';
+import useToast from '@/hooks/use-toast';
+import mergeSx from '@/lib/utils/mergeSx';
+
+import * as styles from './Card.styles';
+import type { CardProps } from './types';
+
+const CardComponent: FC = ({
+ avatar,
+ name,
+ description = '',
+ href = '',
+ children,
+ sx = {},
+}) => {
+ const toast = useToast();
+ const handleDelete = (event: React.MouseEvent) => {
+ event.stopPropagation();
+ toast.success('Deleted', '', 3000);
+ };
+
+ return (
+
+
+
+
+
+
+ {avatar && }
+
+ {name}
+ {children}
+
+
+
+ {description && (
+ {description}
+ )}
+
+
+
+
+
+ );
+};
+
+export const Card = Object.assign(CardComponent, { Position, Price });
+
+export { CardComponent, Position, Price };
diff --git a/src/components/common/ui/card/components/Auto.tsx b/src/components/common/ui/card/components/Auto.tsx
new file mode 100644
index 0000000..2115a57
--- /dev/null
+++ b/src/components/common/ui/card/components/Auto.tsx
@@ -0,0 +1,20 @@
+import { FC } from 'react';
+import { Typography } from '@mui/material';
+
+import * as styles from '@/components/common/ui/card/Card.styles';
+import { AutoProps } from '@/components/common/ui/card/types';
+
+const Auto: FC = ({ auto }) => {
+ return (
+ <>
+ Бренд: {auto.brand}
+ Модель: {auto.model}
+ Рік: {auto.year}
+ VIN код: {auto.vin}
+ Двигун: {auto.engine}
+ Об'єм двигуна: {auto.volume}L
+ >
+ );
+};
+
+export default Auto;
diff --git a/src/components/common/ui/card/components/Phone.tsx b/src/components/common/ui/card/components/Phone.tsx
new file mode 100644
index 0000000..4badc59
--- /dev/null
+++ b/src/components/common/ui/card/components/Phone.tsx
@@ -0,0 +1,11 @@
+import { FC } from 'react';
+import { Typography } from '@mui/material';
+
+import * as styles from '@/components/common/ui/card/Card.styles';
+import type { NumberProps } from '@/components/common/ui/card/types';
+
+const Phone: FC = ({ phone }) => (
+ телефон: {phone}
+);
+
+export default Phone;
diff --git a/src/components/common/ui/card/components/Position.tsx b/src/components/common/ui/card/components/Position.tsx
new file mode 100644
index 0000000..547c87f
--- /dev/null
+++ b/src/components/common/ui/card/components/Position.tsx
@@ -0,0 +1,11 @@
+import { FC } from 'react';
+
+import Tag from '@/components/common/ui/tag';
+
+import type { PositionProps } from '../types';
+
+const Position: FC = ({ position }) => (
+
+);
+
+export default Position;
diff --git a/src/components/common/ui/card/components/Price.tsx b/src/components/common/ui/card/components/Price.tsx
new file mode 100644
index 0000000..73eb374
--- /dev/null
+++ b/src/components/common/ui/card/components/Price.tsx
@@ -0,0 +1,11 @@
+import { FC } from 'react';
+import { Typography } from '@mui/material';
+
+import * as styles from '@/components/common/ui/card/Card.styles';
+import type { PriceProps } from '@/components/common/ui/card/types';
+
+const Price: FC = ({ price }) => (
+ {price}
+);
+
+export default Price;
diff --git a/src/components/common/ui/card/index.ts b/src/components/common/ui/card/index.ts
new file mode 100644
index 0000000..d9c55c8
--- /dev/null
+++ b/src/components/common/ui/card/index.ts
@@ -0,0 +1 @@
+export { Card as default } from './Card';
diff --git a/src/components/common/ui/card/types/index.ts b/src/components/common/ui/card/types/index.ts
new file mode 100644
index 0000000..3b08ad0
--- /dev/null
+++ b/src/components/common/ui/card/types/index.ts
@@ -0,0 +1,29 @@
+import { ReactNode } from 'react';
+import { SxProps, Theme } from '@mui/material/styles';
+
+import { Auto } from '@/types/auto';
+
+export interface CardProps {
+ avatar?: string;
+ name: string;
+ description?: string;
+ href?: string;
+ children?: ReactNode;
+ sx?: SxProps;
+}
+
+export interface PositionProps {
+ position: string;
+}
+
+export interface PriceProps {
+ price: string;
+}
+
+export interface NumberProps {
+ phone: string;
+}
+
+export interface AutoProps {
+ auto: Auto;
+}
diff --git a/src/components/common/ui/icon-button/IconButton.styles.ts b/src/components/common/ui/icon-button/IconButton.styles.ts
new file mode 100644
index 0000000..00cbf3f
--- /dev/null
+++ b/src/components/common/ui/icon-button/IconButton.styles.ts
@@ -0,0 +1,93 @@
+import { SxProps, Theme } from '@mui/material/styles';
+
+import {
+ ButtonColors,
+ IconButtonSize,
+ IconButtonVariant,
+} from '@/components/common/ui/icon-button/types';
+
+const buttonColour: ButtonColors = {
+ contained: {
+ default: {
+ color: 'orange.300',
+ border: 'orange.300',
+ },
+ hover: {
+ color: 'orange.200',
+ border: 'orange.200',
+ },
+ active: {
+ color: 'orange.400',
+ border: 'orange.400',
+ },
+ focused: {
+ color: 'orange.300',
+ border: 'orange.100',
+ },
+ disabled: {
+ color: 'gray.200',
+ border: 'gray.200',
+ },
+ },
+ outlined: {
+ default: {
+ color: 'transparent',
+ border: 'orange.300',
+ },
+ hover: {
+ color: 'rgba(255, 84, 30, 0.15)',
+ border: 'orange.300',
+ },
+ active: {
+ color: 'rgba(255, 84, 30, 0.50)',
+ border: 'orange.300',
+ },
+ focused: {
+ color: 'rgba(255, 84, 30, 0.30)',
+ border: 'orange.300',
+ },
+ disabled: {
+ color: 'transparent',
+ border: 'gray.200',
+ },
+ },
+};
+
+export const button = (
+ size: IconButtonSize,
+ variant: IconButtonVariant,
+): SxProps => ({
+ borderRadius: '6px',
+ border: '2px solid',
+ p: 0,
+ width: size === 'small' ? '36px' : '48px',
+ height: size === 'small' ? '36px' : '48px',
+
+ backgroundColor: buttonColour[variant].default.color,
+ borderColor: buttonColour[variant].default.border,
+ '&:hover': {
+ backgroundColor: buttonColour[variant].hover.color,
+ borderColor: buttonColour[variant].hover.border,
+ },
+ '&:active': {
+ backgroundColor: buttonColour[variant].active.color,
+ borderColor: buttonColour[variant].active.border,
+ },
+ '&:focus': {
+ backgroundColor: buttonColour[variant].focused.color,
+ borderColor: buttonColour[variant].focused.border,
+ },
+ '&:disabled': {
+ backgroundColor: buttonColour[variant].disabled.color,
+ borderColor: buttonColour[variant].disabled.border,
+ svg: {
+ stroke: variant === 'contained' ? 'white' : '#949394',
+ },
+ },
+
+ svg: {
+ width: '24px',
+ height: '24px',
+ stroke: variant === 'contained' ? 'white' : 'black',
+ },
+});
diff --git a/src/components/common/ui/icon-button/IconButton.tsx b/src/components/common/ui/icon-button/IconButton.tsx
new file mode 100644
index 0000000..f8a9b8b
--- /dev/null
+++ b/src/components/common/ui/icon-button/IconButton.tsx
@@ -0,0 +1,45 @@
+import { FC, ReactNode } from 'react';
+import { PlusIcon } from '@heroicons/react/24/outline';
+import {
+ IconButton as IconButtonMUI,
+ IconButtonOwnProps as IconButtonPropsMUI,
+} from '@mui/material';
+import { SxProps, Theme } from '@mui/material/styles';
+
+import {
+ IconButtonSize,
+ IconButtonVariant,
+} from '@/components/common/ui/icon-button/types';
+import mergeSx from '@/lib/utils/mergeSx';
+
+import * as styles from './IconButton.styles';
+
+interface IconButtonProps extends IconButtonPropsMUI {
+ children?: ReactNode;
+ size?: IconButtonSize;
+ variant?: IconButtonVariant;
+ onClick?: () => void;
+ sx?: SxProps;
+}
+
+const IconButton: FC = ({
+ children = ,
+ size = 'medium',
+ variant = 'contained',
+ onClick = () => {},
+ sx = {},
+ ...props
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default IconButton;
diff --git a/src/components/common/ui/icon-button/types/index.ts b/src/components/common/ui/icon-button/types/index.ts
new file mode 100644
index 0000000..4eea48d
--- /dev/null
+++ b/src/components/common/ui/icon-button/types/index.ts
@@ -0,0 +1,31 @@
+export type IconButtonSize = 'small' | 'medium';
+
+export type IconButtonVariant = 'contained' | 'outlined';
+
+export interface ButtonColors {
+ contained: Colors;
+ outlined: Colors;
+}
+
+interface Colors {
+ default: {
+ color: string;
+ border: string;
+ };
+ hover: {
+ color: string;
+ border: string;
+ };
+ active: {
+ color: string;
+ border: string;
+ };
+ focused: {
+ color: string;
+ border: string;
+ };
+ disabled: {
+ color: string;
+ border: string;
+ };
+}
diff --git a/src/components/common/ui/input/Input.styles.ts b/src/components/common/ui/input/Input.styles.ts
index eebae1a..492c1ae 100644
--- a/src/components/common/ui/input/Input.styles.ts
+++ b/src/components/common/ui/input/Input.styles.ts
@@ -4,7 +4,6 @@ import { InputVariant } from '@/components/common/ui/input/types';
export const formControl = (variant: InputVariant): SxProps => ({
'.MuiInputBase-root': {
- m: '10px 0 0 0',
border: '2px solid',
borderColor: 'gray.400',
diff --git a/src/components/common/ui/input/Input.tsx b/src/components/common/ui/input/Input.tsx
index f87496d..7906dd3 100644
--- a/src/components/common/ui/input/Input.tsx
+++ b/src/components/common/ui/input/Input.tsx
@@ -1,7 +1,11 @@
'use client';
import React, { FC, useState } from 'react';
-import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline';
+import {
+ EyeIcon,
+ EyeSlashIcon,
+ MagnifyingGlassIcon,
+} from '@heroicons/react/24/outline';
import {
FormControl,
IconButton,
@@ -28,6 +32,7 @@ interface InputProps extends InputPropsMUI {
password?: boolean;
sx?: SxProps;
fullWidth?: boolean;
+ isSearch?: boolean;
}
const Input: FC = ({
@@ -39,6 +44,7 @@ const Input: FC = ({
password = false,
sx = {},
fullWidth = false,
+ isSearch = false,
...props
}) => {
const [showPassword, setShowPassword] = useState(!password);
@@ -47,16 +53,22 @@ const Input: FC = ({
setShowPassword((prevShowPassword) => !prevShowPassword);
};
- const eyeColor =
+ const iconColor =
variant === 'white' ? theme.palette.gray[300] : theme.palette.gray[400];
+ const startAdornment = isSearch ? (
+
+
+
+ ) : null;
+
const endAdornment = password ? (
{showPassword ? (
-
+
) : (
-
+
)}
@@ -77,6 +89,7 @@ const Input: FC = ({
)}
= {
- width: '100%',
- a: {
- display: 'block',
- p: '12px 20px',
- borderRadius: '6px',
- border: '1px solid',
- borderColor: 'gray.500',
- backgroundColor: 'gray.700',
- boxShadow: '2px 2px 4px 0px rgba(0, 0, 0, 0.25)',
-
- '&:hover': {
- backgroundColor: 'gray.600',
- },
-
- '&:focus': {
- outline: '2px solid',
- outlineColor: 'gray.100',
- },
- },
-};
-
-export const title: SxProps = {
- display: 'flex',
- justifyContent: 'space-between',
-};
-
-export const info: SxProps = {
- display: 'grid',
- gridTemplateColumns: 'auto 1fr',
- columnGap: '20px',
-};
-
-export const avatar: SxProps = {
- width: '64px',
- height: '64px',
- border: '1px solid',
- borderColor: 'gray.500',
-};
-
-export const description: SxProps = {
- mt: '14px',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- display: '-webkit-box',
- WebkitLineClamp: 3,
- WebkitBoxOrient: 'vertical',
-};
diff --git a/src/components/common/ui/organisation-card/OrganisationCard.tsx b/src/components/common/ui/organisation-card/OrganisationCard.tsx
deleted file mode 100644
index 7f3fa2d..0000000
--- a/src/components/common/ui/organisation-card/OrganisationCard.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-'use client';
-import { FC } from 'react';
-import { Avatar, Box, Typography } from '@mui/material';
-import Link from 'next/link';
-
-import Tag from '@/components/common/ui/tag';
-import useToast from '@/hooks/use-toast';
-
-import RoundButtonIcon from '../round-button-icon';
-
-import * as styles from './OrganisationCard.styles';
-
-interface OrganisationCardProps {
- avatar: string;
- name: string;
- position: string;
- description?: string;
-}
-
-const OrganisationCard: FC = ({
- avatar,
- name,
- position,
- description = '',
-}) => {
- const toast = useToast();
- const handleDelete = () => {
- toast.success('Deleted', '', 3000);
- };
-
- const href = 'organisation/1';
-
- return (
-
-
-
-
-
-
-
- {name}
-
-
-
-
-
-
- {description && (
- {description}
- )}
-
-
- );
-};
-
-export default OrganisationCard;
diff --git a/src/components/common/ui/organisation-card/index.ts b/src/components/common/ui/organisation-card/index.ts
deleted file mode 100644
index 0bee94d..0000000
--- a/src/components/common/ui/organisation-card/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './OrganisationCard';
diff --git a/src/components/common/ui/pop-ups/organisation-popup/OrganisationPopup.styles.ts b/src/components/common/ui/pop-ups/organisation-popup/OrganisationPopup.styles.ts
new file mode 100644
index 0000000..19d0230
--- /dev/null
+++ b/src/components/common/ui/pop-ups/organisation-popup/OrganisationPopup.styles.ts
@@ -0,0 +1,40 @@
+import { SxProps, Theme } from '@mui/material/styles';
+
+export const modal: SxProps = {
+ zIndex: 10,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+};
+
+export const window: SxProps = {
+ zIndex: 10,
+ width: '500px',
+ backgroundColor: 'white.main',
+ px: '40px',
+ py: '20px',
+ borderRadius: '6px',
+ border: '1px solid',
+ borderColor: 'grey.500',
+ background: 'white.main',
+};
+
+export const backdrop: SxProps = {
+ background: 'rgba(151, 151, 151, 0.40);',
+ backdropFilter: 'blur(4px)',
+};
+
+export const avatarWrapper: SxProps = {
+ mt: '20px',
+ width: '160px',
+ height: '160px',
+ position: 'relative',
+};
+
+export const buttonIcon: SxProps = {
+ position: 'absolute',
+ right: '0px',
+ top: '120px',
+ margin: 'auto',
+};
diff --git a/src/components/common/ui/pop-ups/organisation-popup/OrganisationPopup.tsx b/src/components/common/ui/pop-ups/organisation-popup/OrganisationPopup.tsx
new file mode 100644
index 0000000..1202933
--- /dev/null
+++ b/src/components/common/ui/pop-ups/organisation-popup/OrganisationPopup.tsx
@@ -0,0 +1,155 @@
+import { FC, PropsWithChildren, useRef, useState } from 'react';
+import { PencilSquareIcon } from '@heroicons/react/24/outline';
+import { Avatar, Box, Modal, Stack, Typography } from '@mui/material';
+import { isAxiosError } from 'axios';
+import { useFormik } from 'formik';
+
+import Button from '@/components/common/ui/button';
+import Input from '@/components/common/ui/input/Input';
+import RoundButtonIcon from '@/components/common/ui/round-button-icon';
+import useToast from '@/hooks/use-toast';
+import OrganisationsAPI from '@/lib/api/organisations/OrganisationsAPI';
+
+import * as styles from './OrganisationPopup.styles';
+
+interface OrganisationPopupProps {
+ open: boolean;
+ handleClick: () => void;
+}
+
+const OrganisationPopup: FC> = ({
+ children,
+ open,
+ handleClick,
+}) => {
+ const toast = useToast();
+
+ const [avatar, setAvatar] = useState(
+ '/svgs/organisation-default.svg',
+ );
+ const fileInputRef = useRef(null);
+
+ const formik = useFormik({
+ initialValues: {
+ avatar: null,
+ name: '',
+ address: '',
+ info: '',
+ },
+ onSubmit: async (values) => {
+ console.log(values);
+ const formData = new FormData();
+ if (values.avatar) {
+ formData.append('avatar', values.avatar as Blob);
+ }
+ formData.append('name', values.name);
+ formData.append('address', values.address);
+ if (values.info) {
+ formData.append('info', values.info);
+ }
+
+ try {
+ await OrganisationsAPI.create(formData);
+ toast.success('Організація створена успішно');
+ handleClick();
+ } catch (error) {
+ if (isAxiosError(error)) {
+ toast.error(
+ 'Помилка при створенні організації',
+ error?.response?.data?.message,
+ );
+ }
+ }
+ },
+ });
+
+ const handleFileChange = (event: React.ChangeEvent) => {
+ const file = event.currentTarget.files?.[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onloadend = () => {
+ setAvatar(reader.result as string);
+ formik.setFieldValue('avatar', file);
+ };
+ reader.readAsDataURL(file);
+ }
+ };
+
+ const handleChangeAvatar = () => {
+ fileInputRef.current?.click();
+ };
+
+ return (
+ <>
+ {children}
+
+
+
+ Створення організації
+
+
+
+
+ >
+ );
+};
+
+export default OrganisationPopup;
diff --git a/src/components/common/ui/pop-ups/organisation-popup/types/index.ts b/src/components/common/ui/pop-ups/organisation-popup/types/index.ts
new file mode 100644
index 0000000..ad512c8
--- /dev/null
+++ b/src/components/common/ui/pop-ups/organisation-popup/types/index.ts
@@ -0,0 +1,4 @@
+export interface ICreateOrganisationContext {
+ open: boolean;
+ handleClick: () => void;
+}
diff --git a/src/components/pages/NotFound.styles.ts b/src/components/pages/NotFound.styles.ts
index f0d1971..1587a3f 100644
--- a/src/components/pages/NotFound.styles.ts
+++ b/src/components/pages/NotFound.styles.ts
@@ -1,16 +1,14 @@
import { SxProps, Theme } from '@mui/material/styles';
export const wrapper: SxProps = {
- height: {
- desktop: '100%',
- mobile: '100vh',
- },
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
- m: '14px 24px 106px 24px',
-
+ m: {
+ mobile: '106px 24px',
+ tablet: '14px 24px 106px 24px',
+ },
img: {
maxWidth: '100%',
height: 'auto',
diff --git a/src/components/pages/auth-pages/login-page/LoginPage.tsx b/src/components/pages/auth-pages/login-page/LoginPage.tsx
index 3d847bc..cc67745 100644
--- a/src/components/pages/auth-pages/login-page/LoginPage.tsx
+++ b/src/components/pages/auth-pages/login-page/LoginPage.tsx
@@ -14,7 +14,6 @@ import SideSection from '@/components/pages/auth-pages/components/side-section';
import useToast from '@/hooks/use-toast';
import AuthAPI from '@/lib/api/auth/AuthAPI';
import { exceptionMapper } from '@/lib/utils/exception-mapper';
-import storageUtil from '@/lib/utils/storageUtil';
import { initialValues } from './constants/initialValues';
import * as styles from './LoginPage.styles';
@@ -26,8 +25,7 @@ const LoginPage: FC = () => {
initialValues,
onSubmit: async (values) => {
try {
- const { accessToken } = await AuthAPI.login(values);
- storageUtil.setToken(accessToken);
+ await AuthAPI.login(values);
router.replace('/profile?tab=organisations');
return;
} catch (e) {
diff --git a/src/hooks/use-auth/useAuth.ts b/src/hooks/use-auth/useAuth.ts
index 186ffa7..39f26b4 100644
--- a/src/hooks/use-auth/useAuth.ts
+++ b/src/hooks/use-auth/useAuth.ts
@@ -10,6 +10,8 @@ const useAuth = () => {
mutate,
} = useSWR('authorization', () => UserAPI.getUser(), {
revalidateOnFocus: false,
+ refreshInterval: 0,
+ revalidateOnReconnect: false,
});
return {
diff --git a/src/lib/api/auth/AuthAPI.ts b/src/lib/api/auth/AuthAPI.ts
index ac78343..9e488cf 100644
--- a/src/lib/api/auth/AuthAPI.ts
+++ b/src/lib/api/auth/AuthAPI.ts
@@ -2,7 +2,6 @@ import { ChangePasswordBody } from '@/lib/api/auth/types/ChangePasswordBody';
import { LoginBody } from '@/lib/api/auth/types/LoginBody';
import { RegisterBody } from '@/lib/api/auth/types/RegisterBody';
import { Token } from '@/lib/api/auth/types/Token';
-import { getAuthorizationHeader } from '@/lib/api/getAuthorizationHeader';
import { instance } from '@/lib/api/instance';
class AuthAPI {
@@ -12,8 +11,7 @@ class AuthAPI {
}
async login(body: LoginBody) {
- const { data } = await instance.post('/auth/login', body);
- return data;
+ await instance.post('/auth/login', body);
}
async approveEmail(token: string) {
@@ -38,11 +36,7 @@ class AuthAPI {
}
async changePassword(values: ChangePasswordBody) {
- await instance.patch(
- '/auth/change/password',
- values,
- getAuthorizationHeader(),
- );
+ await instance.patch('/auth/change/password', values);
}
}
diff --git a/src/lib/api/getAuthorizationHeader.ts b/src/lib/api/getAuthorizationHeader.ts
deleted file mode 100644
index 3a0eda0..0000000
--- a/src/lib/api/getAuthorizationHeader.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import storageUtil from '@/lib/utils/storageUtil';
-
-export const getAuthorizationHeader = () => {
- return {
- headers: {
- Authorization: `Bearer ${storageUtil.getAccessToken()}`,
- },
- };
-};
diff --git a/src/lib/api/instance.ts b/src/lib/api/instance.ts
index 9ca45a9..91e8f71 100644
--- a/src/lib/api/instance.ts
+++ b/src/lib/api/instance.ts
@@ -1,5 +1,8 @@
import axios from 'axios';
-const baseURL = process.env.BASE_URL;
+const baseURL = process.env.NEXT_PUBLIC_API_URL;
-export const instance = axios.create({ baseURL: 'http://localhost:80/' });
+export const instance = axios.create({
+ baseURL,
+ withCredentials: true,
+});
diff --git a/src/lib/api/organisations/OrganisationsAPI.ts b/src/lib/api/organisations/OrganisationsAPI.ts
new file mode 100644
index 0000000..cc8d35c
--- /dev/null
+++ b/src/lib/api/organisations/OrganisationsAPI.ts
@@ -0,0 +1,21 @@
+import { instance } from '@/lib/api/instance';
+import { IOrganisationResponse } from '@/lib/api/organisations/types';
+
+class OrganisationsAPI {
+ async create(body: FormData) {
+ await instance.post('/organizations', body);
+ }
+
+ async getById(id: string) {
+ const { data } = await instance.get(
+ `/organizations/${id}`,
+ );
+ return data;
+ }
+
+ async delete(id: string) {
+ await instance.delete(`/organizations/${id}`);
+ }
+}
+
+export default new OrganisationsAPI();
diff --git a/src/lib/api/organisations/types/index.ts b/src/lib/api/organisations/types/index.ts
new file mode 100644
index 0000000..b253075
--- /dev/null
+++ b/src/lib/api/organisations/types/index.ts
@@ -0,0 +1,6 @@
+export interface IOrganisationResponse {
+ id: string;
+ name: string;
+ avatar: string;
+ address: string;
+}
diff --git a/src/lib/api/user/UserAPI.ts b/src/lib/api/user/UserAPI.ts
index 87ba72a..2ab66a2 100644
--- a/src/lib/api/user/UserAPI.ts
+++ b/src/lib/api/user/UserAPI.ts
@@ -1,29 +1,20 @@
-import { getAuthorizationHeader } from '@/lib/api/getAuthorizationHeader';
import { instance } from '@/lib/api/instance';
import { UserBody, UserInfo } from '@/lib/api/user/types/UserBody';
class UserAPI {
async getUser() {
- const { data } = await instance.get('/auth/user', {
- ...getAuthorizationHeader(),
- });
+ const { data } = await instance.get('/auth/user');
return data;
}
async changePersonalInfo(info: UserInfo) {
- const { data } = await instance.patch('/users', info, {
- ...getAuthorizationHeader(),
- });
+ const { data } = await instance.patch('/users', info);
return data;
}
async changeAvatar(body: FormData) {
- const { data } = await instance.patch(
- '/users/avatar',
- body,
- getAuthorizationHeader(),
- );
+ const { data } = await instance.patch('/users/avatar', body);
return data;
}
}
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..1832542
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,12 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+export async function middleware(request: NextRequest) {
+ const accessToken = request.cookies.get('accessToken');
+ if (!accessToken) {
+ return NextResponse.redirect(new URL('/login', request.url));
+ }
+}
+
+export const config = {
+ matcher: ['/profile/:path*', '/organisations/:path*'],
+};
diff --git a/src/types/auto.ts b/src/types/auto.ts
new file mode 100644
index 0000000..15c093e
--- /dev/null
+++ b/src/types/auto.ts
@@ -0,0 +1,10 @@
+export interface Auto {
+ id: number;
+ number: string;
+ brand: string;
+ model: string;
+ year: number;
+ vin: string;
+ engine: string;
+ volume: number;
+}