From aee3e6a8201649216f52523560aa1dad31dca206 Mon Sep 17 00:00:00 2001 From: Sonny Date: Fri, 6 May 2022 19:35:12 +0200 Subject: [PATCH] Beaucoup trop de chose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout création, édition, suppression catégories & liens - Ajout auth google - Ajout/modification style pour catégories & liens - Ajout component générique pour bouton, inputs, checkbox & selector - Gestion des messages d'erreur/succès/infos via component dédié - Ajout component FormLayout pour les pages création, édition, suppression catégories & liens - Page custom 404, 500 & signin - Modification schéma DB --- .env | 2 +- components/AuthRequired.tsx | 20 + components/Categories/Categories.tsx | 28 +- components/Categories/SideMenu.tsx | 5 +- components/Categories/UserCard.tsx | 3 +- components/Checkbox.tsx | 57 + components/FormLayout.tsx | 55 + components/Links/Links.tsx | 74 +- components/MessageManager.tsx | 14 + components/{input.tsx => TextBox.tsx} | 15 +- components/selector.tsx | 52 +- next.config.js | 16 +- package-lock.json | 6155 +++++++++++++++-- package.json | 13 +- pages/404.tsx | 14 + pages/500.tsx | 14 + pages/_app.tsx | 20 +- pages/_document.tsx | 7 +- pages/api/auth/[...nextauth].js | 30 - pages/api/auth/[...nextauth].ts | 60 + pages/api/category/create.ts | 39 + pages/api/category/edit/[cid].ts | 45 + pages/api/category/remove/[cid].ts | 36 + pages/api/link/create.ts | 68 + pages/api/link/edit/[lid].ts | 59 + pages/api/link/remove/[lid].ts | 36 + pages/category/create.tsx | 90 +- pages/category/edit/[cid].tsx | 109 + pages/category/remove/[cid].tsx | 113 + pages/index.tsx | 52 +- pages/link/create.tsx | 135 +- pages/link/edit/[lid].tsx | 130 + pages/link/remove/[lid].tsx | 122 + pages/signin.tsx | 55 + prisma/schema.prisma | 36 +- public/icons/edit.svg | 3 + public/icons/remove.svg | 3 + redux.ts | 89 - styles/components/message-manager.module.scss | 38 + styles/create.module.scss | 14 + styles/error-page.module.scss | 36 + styles/globals.scss | 40 +- styles/home/categories.module.scss | 91 +- styles/home/links.module.scss | 81 +- styles/login.module.scss | 51 + types.d.ts | 4 +- utils/back.ts | 21 + utils/front.ts | 36 +- 48 files changed, 7164 insertions(+), 1122 deletions(-) create mode 100644 components/AuthRequired.tsx create mode 100644 components/Checkbox.tsx create mode 100644 components/FormLayout.tsx create mode 100644 components/MessageManager.tsx rename components/{input.tsx => TextBox.tsx} (79%) create mode 100644 pages/404.tsx create mode 100644 pages/500.tsx delete mode 100644 pages/api/auth/[...nextauth].js create mode 100644 pages/api/auth/[...nextauth].ts create mode 100644 pages/api/category/create.ts create mode 100644 pages/api/category/edit/[cid].ts create mode 100644 pages/api/category/remove/[cid].ts create mode 100644 pages/api/link/create.ts create mode 100644 pages/api/link/edit/[lid].ts create mode 100644 pages/api/link/remove/[lid].ts create mode 100644 pages/category/edit/[cid].tsx create mode 100644 pages/category/remove/[cid].tsx create mode 100644 pages/link/edit/[lid].tsx create mode 100644 pages/link/remove/[lid].tsx create mode 100644 pages/signin.tsx create mode 100644 public/icons/edit.svg create mode 100644 public/icons/remove.svg delete mode 100644 redux.ts create mode 100644 styles/components/message-manager.module.scss create mode 100644 styles/error-page.module.scss create mode 100644 styles/login.module.scss create mode 100644 utils/back.ts diff --git a/.env b/.env index 046c07c..7602b9d 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -DATABASE_URL="mysql://hp_user:oxU9ExgAHXktIhQZ@79.143.186.18:3306/Superpipo" \ No newline at end of file +DATABASE_URL="mysql://root:@localhost:3306/superpipo" \ No newline at end of file diff --git a/components/AuthRequired.tsx b/components/AuthRequired.tsx new file mode 100644 index 0000000..b27318e --- /dev/null +++ b/components/AuthRequired.tsx @@ -0,0 +1,20 @@ +import { useSession } from 'next-auth/react' +import { useRouter } from 'next/router'; + +export default function Auth({ children }) { + const router = useRouter(); + const { status } = useSession({ + required: true, + onUnauthenticated: () => router.push(`/signin?info=${encodeURI('Vous devez être connecté pour accéder à cette page')}`) + }); + + if (status === 'loading') { + return ( +
+

Chargement de la session en cours

+
+ ); + } + + return children; +} \ No newline at end of file diff --git a/components/Categories/Categories.tsx b/components/Categories/Categories.tsx index d8ea1e4..25f19ab 100644 --- a/components/Categories/Categories.tsx +++ b/components/Categories/Categories.tsx @@ -1,6 +1,11 @@ +import LinkTag from 'next/link'; + import styles from '../../styles/home/categories.module.scss'; import { Category } from '../../types'; +import EditSVG from '../../public/icons/edit.svg'; +import RemoveSVG from '../../public/icons/remove.svg'; + interface CategoriesProps { categories: Category[]; categoryActive: Category; @@ -35,7 +40,28 @@ function CategoryItem({ category, categoryActive, handleSelectCategory }: Catego return (
  • - {category.name} — {category.links.length} +
    + {category.name} + — {category.links.length} +
    +
  • ) +} + +function MenuOptions({ id }: { id: number; }): JSX.Element { + return ( +
    + + + + + + + + + + +
    + ) } \ No newline at end of file diff --git a/components/Categories/SideMenu.tsx b/components/Categories/SideMenu.tsx index 58bb1ab..174bb05 100644 --- a/components/Categories/SideMenu.tsx +++ b/components/Categories/SideMenu.tsx @@ -1,12 +1,13 @@ import { Session } from 'next-auth'; import LinkTag from 'next/link'; -import styles from '../../styles/home/categories.module.scss'; -import { Category, Link } from '../../types'; import Categories from './Categories'; import Favorites from './Favorites'; import UserCard from './UserCard'; +import styles from '../../styles/home/categories.module.scss'; +import { Category, Link } from '../../types'; + interface SideMenuProps { categories: Category[]; favorites: Link[]; diff --git a/components/Categories/UserCard.tsx b/components/Categories/UserCard.tsx index 1a0a7bf..df7242d 100644 --- a/components/Categories/UserCard.tsx +++ b/components/Categories/UserCard.tsx @@ -1,6 +1,7 @@ import { Session } from 'next-auth'; import { signOut } from 'next-auth/react'; import Image from 'next/image'; + import styles from '../../styles/home/categories.module.scss'; export default function UserCard({ session }: { session: Session; }) { @@ -15,7 +16,7 @@ export default function UserCard({ session }: { session: Session; }) { /> {session.user.name} - diff --git a/components/Checkbox.tsx b/components/Checkbox.tsx new file mode 100644 index 0000000..be00fd5 --- /dev/null +++ b/components/Checkbox.tsx @@ -0,0 +1,57 @@ +import { MutableRefObject, useState } from 'react'; + +interface SelectorProps { + name: string; + label?: string; + labelComponent?: JSX.Element; + disabled?: boolean; + innerRef?: MutableRefObject; + placeholder?: string; + fieldClass?: string; + isChecked?: boolean; + onChangeCallback?: (value, { target }) => void; +} + +export default function Selector({ + name, + label, + labelComponent, + disabled = false, + innerRef = null, + fieldClass = '', + placeholder = 'Type something...', + isChecked, + onChangeCallback +}: SelectorProps): JSX.Element { + const [checkboxValue, setCheckboxValue] = useState(isChecked); + + function onChange({ target }) { + setCheckboxValue(!checkboxValue); + if (onChangeCallback) { + onChangeCallback(!checkboxValue, { target }); + } + } + + return (
    + {label && ( + + )} + {labelComponent && ( + + )} + +
    ); +} \ No newline at end of file diff --git a/components/FormLayout.tsx b/components/FormLayout.tsx new file mode 100644 index 0000000..b8e0a45 --- /dev/null +++ b/components/FormLayout.tsx @@ -0,0 +1,55 @@ +import Head from 'next/head'; +import Link from 'next/link'; + +import MessageManager from './MessageManager'; + +import styles from '../styles/create.module.scss'; + +interface FormProps { + title: string; + errorMessage?: string; + successMessage?: string; + infoMessage?: string; + + canSubmit: boolean; + handleSubmit: (event) => void; + + textBtnConfirm?: string; + classBtnConfirm?: string; + + children: any; +} +export default function Form({ + title, + errorMessage, + successMessage, + infoMessage, + canSubmit, + handleSubmit, + textBtnConfirm = 'Valider', + classBtnConfirm = '', + children +}: FormProps) { + return (<> + + Superpipo — {title} + +
    +

    {title}

    +
    + {children} + +
    + + ← Revenir à l'accueil + + +
    + ) +} \ No newline at end of file diff --git a/components/Links/Links.tsx b/components/Links/Links.tsx index 28d88c6..0340b71 100644 --- a/components/Links/Links.tsx +++ b/components/Links/Links.tsx @@ -1,8 +1,12 @@ import LinkTag from 'next/link'; -import styles from '../../styles/home/links.module.scss'; import { Category, Link } from '../../types'; +import EditSVG from '../../public/icons/edit.svg'; +import RemoveSVG from '../../public/icons/remove.svg'; + +import styles from '../../styles/home/links.module.scss'; + export default function Links({ category }: { category: Category; }) { if (category === null) { return (
    @@ -25,7 +29,7 @@ export default function Links({ category }: { category: Category; }) { return (

    {name} — {links.length}

    -
      +
        {links.map((link, key) => ( ))} @@ -34,42 +38,58 @@ export default function Links({ category }: { category: Category; }) { } function LinkItem({ link }: { link: Link; }) { - const { name, url, category } = link; - const { origin, pathname, search } = new URL(url); - + const { id, name, url, category } = link; return ( -
      • +
      • {name} — {category.name} - + +
        + + + + + + + + + + +
      • ); } -function LinkItemURL({ origin, pathname, search }) { - let text = ''; +function LinkItemURL({ url }: { url: string; }) { + try { + const { origin, pathname, search } = new URL(url); + let text = ''; - if (pathname !== '/') { - text += pathname; - } - - if (search !== '') { - if (text === '') { - text += '/'; + if (pathname !== '/') { + text += pathname; } - text += search; - } - return ( - - {origin}{text} - - ) + if (search !== '') { + if (text === '') { + text += '/'; + } + text += search; + } + + return ( + + {origin}{text} + + ) + } catch (error) { + console.error('error', error); + return ( + + {url} + + ) + } } \ No newline at end of file diff --git a/components/MessageManager.tsx b/components/MessageManager.tsx new file mode 100644 index 0000000..9e86ada --- /dev/null +++ b/components/MessageManager.tsx @@ -0,0 +1,14 @@ +import styles from '../styles/components/message-manager.module.scss'; + +interface MessageManagerProps { + error?: string; + success?: string; + info?: string; +} +export default function MessageManager({ error, success, info }: MessageManagerProps) { + return (<> + {info && (
        {info}
        )} + {error && (
        {error}
        )} + {success && (
        {success}
        )} + ); +} \ No newline at end of file diff --git a/components/input.tsx b/components/TextBox.tsx similarity index 79% rename from components/input.tsx rename to components/TextBox.tsx index 9c4614b..d21e4ba 100644 --- a/components/input.tsx +++ b/components/TextBox.tsx @@ -1,22 +1,24 @@ -import { MutableRefObject, useState } from "react"; +import { MutableRefObject, useState } from 'react'; interface InputProps { name: string; label?: string; labelComponent?: JSX.Element; + disabled?: boolean; type?: string; multiple?: boolean; innerRef?: MutableRefObject; placeholder?: string; fieldClass?: string; value?: string; - onChangeCallback: ({ target }, value) => void; + onChangeCallback?: (value) => void; } -export default function Input({ +export default function TextBox({ name, label, labelComponent, + disabled = false, type = 'text', multiple = false, innerRef = null, @@ -29,7 +31,9 @@ export default function Input({ function onChange({ target }) { setInputValue(target.value); - onChangeCallback({ target }, target.value); + if (onChangeCallback) { + onChangeCallback(target.value); + } } return (
        @@ -38,7 +42,7 @@ export default function Input({ {label} )} - {!!labelComponent && ( + {labelComponent && ( @@ -52,6 +56,7 @@ export default function Input({ multiple={multiple} placeholder={placeholder} ref={innerRef} + disabled={disabled} />
        ); } \ No newline at end of file diff --git a/components/selector.tsx b/components/selector.tsx index b52f1f4..77e4dcd 100644 --- a/components/selector.tsx +++ b/components/selector.tsx @@ -1,4 +1,7 @@ -import { MutableRefObject, useState } from "react"; +import { MutableRefObject, useEffect, useState } from 'react'; +import Select, { OptionsOrGroups, GroupBase } from 'react-select'; + +type Option = { label: string | number; value: string | number; } interface SelectorProps { name: string; @@ -6,9 +9,12 @@ interface SelectorProps { labelComponent?: JSX.Element; innerRef?: MutableRefObject; fieldClass?: string; - value?: string | number; - onChangeCallback: ({ target }, value) => void; - children?: any; + + options: OptionsOrGroups>; + value?: number | string; + onChangeCallback?: (value: number | string) => void; + + disabled?: boolean; } export default function Selector({ @@ -18,14 +24,26 @@ export default function Selector({ innerRef = null, fieldClass = '', value, + options = [], onChangeCallback, - children + disabled = false }: SelectorProps): JSX.Element { - const [inputValue, setInputValue] = useState(value); + const [selectorValue, setSelectorValue] = useState