From d8fab085855d5df673409d2f1ac6231299980a8b Mon Sep 17 00:00:00 2001
From: Divlo
Date: Tue, 26 Oct 2021 16:38:55 +0200
Subject: [PATCH] feat: create a guild (#1)
---
components/Application/Application.tsx | 13 +-
.../CreateGuild/CreateGuild.stories.tsx | 15 ++
.../Application/CreateGuild/CreateGuild.tsx | 82 ++++++++++
components/Application/CreateGuild/index.ts | 1 +
.../UserProfile/UserProfile.stories.tsx | 2 +-
.../UserProfile/UserProfile.test.tsx | 2 +-
.../UserProfile/UserProfile.tsx | 4 +-
.../{ => Application}/UserProfile/index.ts | 0
components/Authentication/Authentication.tsx | 147 ++++++------------
cypress/fixtures/channels/channel.ts | 9 ++
cypress/fixtures/guilds/guild.ts | 8 +
cypress/fixtures/guilds/post.ts | 20 +++
cypress/fixtures/members/member.ts | 16 ++
cypress/fixtures/users/user.ts | 13 +-
.../pages/application/guilds/create.spec.ts | 37 +++++
.../authentication/reset-password.spec.ts | 5 +-
.../useForm}/getErrorTranslationKey.test.ts | 0
.../useForm}/getErrorTranslationKey.ts | 0
hooks/useForm/index.ts | 1 +
hooks/useForm/useForm.ts | 108 +++++++++++++
hooks/{useFormState.tsx => useFormState.ts} | 0
i18n.json | 5 +-
locales/en/application.json | 4 +-
locales/en/authentication.json | 1 -
locales/en/common.json | 3 +-
locales/fr/application.json | 4 +-
locales/fr/authentication.json | 1 -
locales/fr/common.json | 3 +-
models/Channel.ts | 2 +-
models/Guild.ts | 20 ++-
models/Message.ts | 7 +-
models/User.ts | 40 ++---
next.config.js | 6 +
package-lock.json | 41 +++--
package.json | 1 +
pages/application/guilds/create.tsx | 68 +-------
pages/application/users/[userId].tsx | 3 +-
pages/authentication/forgot-password.tsx | 67 +++-----
pages/authentication/reset-password.tsx | 61 +++-----
public/images/data/divlo.png | Bin 41784 -> 0 bytes
public/images/data/user-default.png | Bin 0 -> 9359 bytes
utils/authentication/Authentication.ts | 5 +-
.../authentication/AuthenticationContext.tsx | 4 +-
.../authenticationFromServerSide.ts | 14 +-
utils/authentication/index.ts | 2 +-
45 files changed, 530 insertions(+), 315 deletions(-)
create mode 100644 components/Application/CreateGuild/CreateGuild.stories.tsx
create mode 100644 components/Application/CreateGuild/CreateGuild.tsx
create mode 100644 components/Application/CreateGuild/index.ts
rename components/{ => Application}/UserProfile/UserProfile.stories.tsx (84%)
rename components/{ => Application}/UserProfile/UserProfile.test.tsx (81%)
rename components/{ => Application}/UserProfile/UserProfile.tsx (99%)
rename components/{ => Application}/UserProfile/index.ts (100%)
create mode 100644 cypress/fixtures/channels/channel.ts
create mode 100644 cypress/fixtures/guilds/guild.ts
create mode 100644 cypress/fixtures/guilds/post.ts
create mode 100644 cypress/fixtures/members/member.ts
create mode 100644 cypress/integration/pages/application/guilds/create.spec.ts
rename {components/Authentication => hooks/useForm}/getErrorTranslationKey.test.ts (100%)
rename {components/Authentication => hooks/useForm}/getErrorTranslationKey.ts (100%)
create mode 100644 hooks/useForm/index.ts
create mode 100644 hooks/useForm/useForm.ts
rename hooks/{useFormState.tsx => useFormState.ts} (100%)
delete mode 100644 public/images/data/divlo.png
create mode 100644 public/images/data/user-default.png
diff --git a/components/Application/Application.tsx b/components/Application/Application.tsx
index 944f74f..e8214c2 100644
--- a/components/Application/Application.tsx
+++ b/components/Application/Application.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect, useMemo } from 'react'
import Image from 'next/image'
+import useTranslation from 'next-translate/useTranslation'
import {
CogIcon,
PlusIcon,
@@ -19,6 +20,7 @@ import { Guilds } from './Guilds/Guilds'
import { Divider } from '../design/Divider'
import { Members } from './Members'
import { useAuthentication } from 'utils/authentication'
+import { API_URL } from 'utils/api'
export interface GuildsChannelsPath {
guildId: number
@@ -37,6 +39,7 @@ export interface ApplicationProps {
export const Application: React.FC = (props) => {
const { children, path } = props
+ const { t } = useTranslation()
const { user } = useAuthentication()
const [visibleSidebars, setVisibleSidebars] = useState({
@@ -138,10 +141,10 @@ export const Application: React.FC = (props) => {
return 'Join a Guild'
}
if (path === '/application/guilds/create') {
- return 'Create a Guild'
+ return t('application:create-a-guild')
}
return 'Application'
- }, [path])
+ }, [path, t])
useEffect(() => {
setMounted(true)
@@ -193,7 +196,11 @@ export const Application: React.FC = (props) => {
>
{
+ return
+}
+CreateGuild.args = {}
diff --git a/components/Application/CreateGuild/CreateGuild.tsx b/components/Application/CreateGuild/CreateGuild.tsx
new file mode 100644
index 0000000..b2fd563
--- /dev/null
+++ b/components/Application/CreateGuild/CreateGuild.tsx
@@ -0,0 +1,82 @@
+import { useRouter } from 'next/router'
+import useTranslation from 'next-translate/useTranslation'
+import { Form } from 'react-component-form'
+import TextareaAutosize from 'react-textarea-autosize'
+import { AxiosResponse } from 'axios'
+
+import { useAuthentication } from '../../../utils/authentication'
+import { HandleSubmitCallback, useForm } from '../../../hooks/useForm'
+import { GuildComplete, guildSchema } from '../../../models/Guild'
+import { Input } from '../../design/Input'
+import { Main } from '../../design/Main'
+import { Button } from '../../design/Button'
+import { FormState } from '../../design/FormState'
+
+export const CreateGuild: React.FC = () => {
+ const { t } = useTranslation()
+ const router = useRouter()
+
+ const { formState, message, errors, getErrorTranslation, handleSubmit } =
+ useForm({
+ validateSchemaObject: {
+ name: guildSchema.name,
+ description: guildSchema.description
+ }
+ })
+
+ const { authentication } = useAuthentication()
+
+ const onSubmit: HandleSubmitCallback = async (formData) => {
+ try {
+ const { data } = await authentication.api.post<
+ any,
+ AxiosResponse<{ guild: GuildComplete }>
+ >('/guilds', { name: formData.name, description: formData.description })
+ const guildId = data.guild.id
+ const channelId = data.guild.channels[0].id
+ await router.push(`/application/${guildId}/${channelId}`)
+ return null
+ } catch (error) {
+ return {
+ type: 'error',
+ value: 'errors:server-error'
+ }
+ }
+ }
+
+ return (
+
+
+
+
+ )
+}
diff --git a/components/Application/CreateGuild/index.ts b/components/Application/CreateGuild/index.ts
new file mode 100644
index 0000000..cc03400
--- /dev/null
+++ b/components/Application/CreateGuild/index.ts
@@ -0,0 +1 @@
+export * from './CreateGuild'
diff --git a/components/UserProfile/UserProfile.stories.tsx b/components/Application/UserProfile/UserProfile.stories.tsx
similarity index 84%
rename from components/UserProfile/UserProfile.stories.tsx
rename to components/Application/UserProfile/UserProfile.stories.tsx
index e8e6953..ee76ced 100644
--- a/components/UserProfile/UserProfile.stories.tsx
+++ b/components/Application/UserProfile/UserProfile.stories.tsx
@@ -1,5 +1,5 @@
import { Meta, Story } from '@storybook/react'
-import { user, userSettings } from '../../cypress/fixtures/users/user'
+import { user, userSettings } from '../../../cypress/fixtures/users/user'
import { UserProfile as Component, UserProfileProps } from './UserProfile'
diff --git a/components/UserProfile/UserProfile.test.tsx b/components/Application/UserProfile/UserProfile.test.tsx
similarity index 81%
rename from components/UserProfile/UserProfile.test.tsx
rename to components/Application/UserProfile/UserProfile.test.tsx
index fa7d128..08a07a7 100644
--- a/components/UserProfile/UserProfile.test.tsx
+++ b/components/Application/UserProfile/UserProfile.test.tsx
@@ -1,6 +1,6 @@
import { render } from '@testing-library/react'
-import { user, userSettings } from '../../cypress/fixtures/users/user'
+import { user, userSettings } from '../../../cypress/fixtures/users/user'
import { UserProfile } from './UserProfile'
diff --git a/components/UserProfile/UserProfile.tsx b/components/Application/UserProfile/UserProfile.tsx
similarity index 99%
rename from components/UserProfile/UserProfile.tsx
rename to components/Application/UserProfile/UserProfile.tsx
index c1bb81f..38a6f04 100644
--- a/components/UserProfile/UserProfile.tsx
+++ b/components/Application/UserProfile/UserProfile.tsx
@@ -4,7 +4,7 @@ import classNames from 'classnames'
import useTranslation from 'next-translate/useTranslation'
import date from 'date-and-time'
-import { UserPublic } from '../../models/User'
+import { UserPublic } from '../../../models/User'
export interface UserProfileProps {
className?: string
@@ -15,8 +15,6 @@ export interface UserProfileProps {
export const UserProfile: React.FC = (props) => {
const { user, isOwner = false } = props
- console.log(user)
-
const { t } = useTranslation()
const handleSubmitChanges = (
diff --git a/components/UserProfile/index.ts b/components/Application/UserProfile/index.ts
similarity index 100%
rename from components/UserProfile/index.ts
rename to components/Application/UserProfile/index.ts
diff --git a/components/Authentication/Authentication.tsx b/components/Authentication/Authentication.tsx
index 587b48d..d1621ac 100644
--- a/components/Authentication/Authentication.tsx
+++ b/components/Authentication/Authentication.tsx
@@ -1,11 +1,7 @@
-import { useMemo, useState } from 'react'
import { useRouter } from 'next/router'
import Link from 'next/link'
import useTranslation from 'next-translate/useTranslation'
import { useTheme } from 'next-themes'
-import { Type } from '@sinclair/typebox'
-import type { ErrorObject } from 'ajv'
-import type { HandleForm } from 'react-component-form'
import axios from 'axios'
import { SocialMediaButton } from '../design/SocialMediaButton'
@@ -13,26 +9,14 @@ import { Main } from '../design/Main'
import { Input } from '../design/Input'
import { Button } from '../design/Button'
import { FormState } from '../design/FormState'
-import { useFormState } from '../../hooks/useFormState'
import { AuthenticationForm } from './'
import { userSchema } from '../../models/User'
-import { ajv } from '../../utils/ajv'
import { api } from 'utils/api'
import {
Tokens,
Authentication as AuthenticationClass
} from '../../utils/authentication'
-import { getErrorTranslationKey } from './getErrorTranslationKey'
-
-interface Errors {
- [key: string]: ErrorObject | null | undefined
-}
-
-const findError = (
- field: string
-): ((value: ErrorObject, index: number, object: ErrorObject[]) => boolean) => {
- return (validationError) => validationError.instancePath === field
-}
+import { useForm, HandleSubmitCallback } from '../../hooks/useForm'
export interface AuthenticationProps {
mode: 'signup' | 'signin'
@@ -44,84 +28,57 @@ export const Authentication: React.FC = (props) => {
const router = useRouter()
const { lang, t } = useTranslation()
const { theme } = useTheme()
- const [formState, setFormState] = useFormState()
- const [messageTranslationKey, setMessageTranslationKey] = useState<
- string | undefined
- >(undefined)
- const [errors, setErrors] = useState({
- name: null,
- email: null,
- password: null
- })
- const validateSchema = useMemo(() => {
- return Type.Object({
- ...(mode === 'signup' && { name: userSchema.name }),
- email: userSchema.email,
- password: userSchema.password
+ const { errors, formState, message, getErrorTranslation, handleSubmit } =
+ useForm({
+ validateSchemaObject: {
+ ...(mode === 'signup' && { name: userSchema.name }),
+ email: userSchema.email,
+ password: userSchema.password
+ }
})
- }, [mode])
- const validate = useMemo(() => {
- return ajv.compile(validateSchema)
- }, [validateSchema])
-
- const getErrorTranslation = (error?: ErrorObject | null): string | null => {
- if (error != null) {
- return t(getErrorTranslationKey(error)).replace(
- '{expected}',
- error?.params?.limit
- )
- }
- return null
- }
-
- const handleSubmit: HandleForm = async (formData, formElement) => {
- const isValid = validate(formData)
- if (!isValid) {
- setFormState('error')
- const nameError = validate?.errors?.find(findError('/name'))
- const emailError = validate?.errors?.find(findError('/email'))
- const passwordError = validate?.errors?.find(findError('/password'))
- setErrors({
- name: nameError,
- email: emailError,
- password: passwordError
- })
- } else {
- setErrors({})
- setFormState('loading')
- if (mode === 'signup') {
- try {
- await api.post(
- `/users/signup?redirectURI=${window.location.origin}/authentication/signin`,
- { ...formData, language: lang, theme }
- )
- formElement.reset()
- setFormState('success')
- setMessageTranslationKey('authentication:success-signup')
- } catch (error) {
- setFormState('error')
- if (axios.isAxiosError(error) && error.response?.status === 400) {
- setMessageTranslationKey('authentication:alreadyUsed')
- } else {
- setMessageTranslationKey('errors:server-error')
+ const onSubmit: HandleSubmitCallback = async (formData) => {
+ if (mode === 'signup') {
+ try {
+ await api.post(
+ `/users/signup?redirectURI=${window.location.origin}/authentication/signin`,
+ { ...formData, language: lang, theme }
+ )
+ return {
+ type: 'success',
+ value: 'authentication:success-signup'
+ }
+ } catch (error) {
+ if (axios.isAxiosError(error) && error.response?.status === 400) {
+ return {
+ type: 'error',
+ value: 'authentication:alreadyUsed'
}
}
- } else {
- try {
- const { data } = await api.post('/users/signin', formData)
- const authentication = new AuthenticationClass(data)
- authentication.signin()
- await router.push('/application')
- } catch (error) {
- setFormState('error')
- if (axios.isAxiosError(error) && error.response?.status === 400) {
- setMessageTranslationKey('authentication:wrong-credentials')
- } else {
- setMessageTranslationKey('errors:server-error')
+ return {
+ type: 'error',
+ value: 'errors:server-error'
+ }
+ }
+ } else {
+ try {
+ const { data } = await api.post('/users/signin', formData)
+ const authentication = new AuthenticationClass(data)
+ authentication.signin()
+ await router.push('/application')
+ return null
+ } catch (error) {
+ if (axios.isAxiosError(error) && error.response?.status === 400) {
+ return {
+ type: 'error',
+ value: 'authentication:wrong-credentials'
}
}
+ return {
+ type: 'error',
+ value: 'errors:server-error'
+ }
}
}
}
@@ -138,13 +95,13 @@ export const Authentication: React.FC = (props) => {
-
+
{mode === 'signup' && (
)}
@@ -182,13 +139,7 @@ export const Authentication: React.FC = (props) => {
-
+
)
}
diff --git a/cypress/fixtures/channels/channel.ts b/cypress/fixtures/channels/channel.ts
new file mode 100644
index 0000000..dc221f3
--- /dev/null
+++ b/cypress/fixtures/channels/channel.ts
@@ -0,0 +1,9 @@
+import { guild } from '../guilds/guild'
+
+export const channel = {
+ id: 1,
+ name: 'general',
+ guildId: guild.id,
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString()
+}
diff --git a/cypress/fixtures/guilds/guild.ts b/cypress/fixtures/guilds/guild.ts
new file mode 100644
index 0000000..bcd9a50
--- /dev/null
+++ b/cypress/fixtures/guilds/guild.ts
@@ -0,0 +1,8 @@
+export const guild = {
+ id: 1,
+ name: 'GuildExample',
+ description: 'guild example.',
+ icon: null,
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString()
+}
diff --git a/cypress/fixtures/guilds/post.ts b/cypress/fixtures/guilds/post.ts
new file mode 100644
index 0000000..8feefa3
--- /dev/null
+++ b/cypress/fixtures/guilds/post.ts
@@ -0,0 +1,20 @@
+import { Handler } from '../handler'
+
+import { guild } from './guild'
+import { channel } from '../channels/channel'
+import { memberComplete } from '../members/member'
+
+export const postGuildsHandler: Handler = {
+ method: 'POST',
+ url: '/guilds',
+ response: {
+ statusCode: 201,
+ body: {
+ guild: {
+ ...guild,
+ channels: [channel],
+ members: [memberComplete]
+ }
+ }
+ }
+}
diff --git a/cypress/fixtures/members/member.ts b/cypress/fixtures/members/member.ts
new file mode 100644
index 0000000..46872c7
--- /dev/null
+++ b/cypress/fixtures/members/member.ts
@@ -0,0 +1,16 @@
+import { guild } from '../guilds/guild'
+import { user } from '../users/user'
+
+export const member = {
+ id: 1,
+ isOwner: true,
+ userId: user.id,
+ guildId: guild.id,
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString()
+}
+
+export const memberComplete = {
+ ...member,
+ user
+}
diff --git a/cypress/fixtures/users/user.ts b/cypress/fixtures/users/user.ts
index 0024a65..d43dcb9 100644
--- a/cypress/fixtures/users/user.ts
+++ b/cypress/fixtures/users/user.ts
@@ -1,15 +1,18 @@
import { UserSettings } from '../../../models/UserSettings'
-import { UserPublic } from '../../../models/User'
+import { User } from '../../../models/User'
-export const user: UserPublic = {
+export const user: User = {
id: 1,
name: 'Divlo',
email: 'contact@divlo.fr',
- logo: undefined,
- status: undefined,
- biography: undefined,
+ password: 'somepassword',
+ logo: null,
+ status: null,
+ biography: null,
website: 'https://divlo.fr',
isConfirmed: true,
+ temporaryToken: 'temporaryUUIDtoken',
+ temporaryExpirationToken: '2021-10-20T20:59:08.485Z',
createdAt: '2021-10-20T20:30:51.595Z',
updatedAt: '2021-10-20T20:59:08.485Z'
}
diff --git a/cypress/integration/pages/application/guilds/create.spec.ts b/cypress/integration/pages/application/guilds/create.spec.ts
new file mode 100644
index 0000000..e276376
--- /dev/null
+++ b/cypress/integration/pages/application/guilds/create.spec.ts
@@ -0,0 +1,37 @@
+import { channel } from '../../../../fixtures/channels/channel'
+import { guild } from '../../../../fixtures/guilds/guild'
+import { postGuildsHandler } from '../../../../fixtures/guilds/post'
+import { authenticationHandlers } from '../../../../fixtures/handler'
+
+describe('Pages > /application/guilds/create', () => {
+ beforeEach(() => {
+ cy.task('stopMockServer')
+ })
+
+ it('should succeeds and create the guild', () => {
+ cy.task('startMockServer', [
+ ...authenticationHandlers,
+ postGuildsHandler
+ ]).setCookie('refreshToken', 'refresh-token')
+ cy.visit('/application/guilds/create')
+ cy.get('#error-name').should('not.exist')
+ cy.get('[data-cy=input-name]').type(guild.name)
+ cy.get('[data-cy=submit]').click()
+ cy.location('pathname').should(
+ 'eq',
+ `/application/${guild.id}/${channel.id}`
+ )
+ })
+
+ it('should fails with internal api server error', () => {
+ cy.task('startMockServer', [...authenticationHandlers]).setCookie(
+ 'refreshToken',
+ 'refresh-token'
+ )
+ cy.visit('/application/guilds/create')
+ cy.get('#error-name').should('not.exist')
+ cy.get('[data-cy=input-name]').type(guild.name)
+ cy.get('[data-cy=submit]').click()
+ cy.get('#message').should('have.text', 'Error: Internal Server Error.')
+ })
+})
diff --git a/cypress/integration/pages/authentication/reset-password.spec.ts b/cypress/integration/pages/authentication/reset-password.spec.ts
index 7195389..74e1460 100644
--- a/cypress/integration/pages/authentication/reset-password.spec.ts
+++ b/cypress/integration/pages/authentication/reset-password.spec.ts
@@ -40,6 +40,9 @@ describe('Pages > /authentication/reset-password', () => {
cy.visit('/authentication/reset-password')
cy.get('#message').should('not.exist')
cy.get('[data-cy=submit]').click()
- cy.get('#message').should('have.text', 'Error: Invalid value.')
+ cy.get('#message').should(
+ 'have.text',
+ 'Error: Oops, this field is required đ.'
+ )
})
})
diff --git a/components/Authentication/getErrorTranslationKey.test.ts b/hooks/useForm/getErrorTranslationKey.test.ts
similarity index 100%
rename from components/Authentication/getErrorTranslationKey.test.ts
rename to hooks/useForm/getErrorTranslationKey.test.ts
diff --git a/components/Authentication/getErrorTranslationKey.ts b/hooks/useForm/getErrorTranslationKey.ts
similarity index 100%
rename from components/Authentication/getErrorTranslationKey.ts
rename to hooks/useForm/getErrorTranslationKey.ts
diff --git a/hooks/useForm/index.ts b/hooks/useForm/index.ts
new file mode 100644
index 0000000..f65863c
--- /dev/null
+++ b/hooks/useForm/index.ts
@@ -0,0 +1 @@
+export * from './useForm'
diff --git a/hooks/useForm/useForm.ts b/hooks/useForm/useForm.ts
new file mode 100644
index 0000000..c3489c2
--- /dev/null
+++ b/hooks/useForm/useForm.ts
@@ -0,0 +1,108 @@
+import { useMemo, useState } from 'react'
+import useTranslation from 'next-translate/useTranslation'
+import { Type } from '@sinclair/typebox'
+import type { FormDataObject, HandleForm } from 'react-component-form'
+import type { ErrorObject } from 'ajv'
+
+import { FormState, useFormState } from '../useFormState'
+import { ajv } from '../../utils/ajv'
+import { getErrorTranslationKey } from './getErrorTranslationKey'
+
+interface Errors {
+ [key: string]: ErrorObject | null | undefined
+}
+
+const findError = (
+ field: string
+): ((value: ErrorObject, index: number, object: ErrorObject[]) => boolean) => {
+ return (validationError) => validationError.instancePath === field
+}
+
+export type GetErrorTranslation = (error?: ErrorObject | null) => string | null
+
+export interface UseFormOptions {
+ validateSchemaObject: { [key: string]: any }
+}
+
+export type HandleSubmit = (callback: HandleSubmitCallback) => HandleForm
+
+interface Message {
+ type: 'error' | 'success'
+ value: string
+}
+
+export type HandleSubmitCallback = (
+ formData: FormDataObject,
+ formElement: HTMLFormElement
+) => Promise
+
+export interface UseFormResult {
+ message: string | null
+ formState: FormState
+ getErrorTranslation: GetErrorTranslation
+ handleSubmit: HandleSubmit
+ errors: Errors
+}
+
+export const useForm = (options: UseFormOptions): UseFormResult => {
+ const { validateSchemaObject } = options
+ const { t } = useTranslation()
+ const [formState, setFormState] = useFormState()
+ const [messageTranslationKey, setMessageTranslationKey] = useState<
+ string | undefined
+ >(undefined)
+ const [errors, setErrors] = useState({})
+
+ const validateSchema = useMemo(() => {
+ return Type.Object(validateSchemaObject)
+ }, [validateSchemaObject])
+
+ const validate = useMemo(() => {
+ return ajv.compile(validateSchema)
+ }, [validateSchema])
+
+ const getErrorTranslation = (error?: ErrorObject | null): string | null => {
+ if (error != null) {
+ return t(getErrorTranslationKey(error)).replace(
+ '{expected}',
+ error?.params?.limit
+ )
+ }
+ return null
+ }
+
+ const handleSubmit: HandleSubmit = (callback) => {
+ return async (formData, formElement) => {
+ const isValid = validate(formData)
+ if (!isValid) {
+ setFormState('error')
+ const errors: Errors = {}
+ for (const property in validateSchema.properties) {
+ errors[property] = validate.errors?.find(findError(`/${property}`))
+ }
+ setErrors(errors)
+ } else {
+ setErrors({})
+ setFormState('loading')
+ const message = await callback(formData, formElement)
+ if (message != null) {
+ setMessageTranslationKey(message.value)
+ if (message.type === 'success') {
+ setFormState('success')
+ formElement.reset()
+ } else {
+ setFormState('error')
+ }
+ }
+ }
+ }
+ }
+
+ return {
+ getErrorTranslation,
+ errors,
+ formState,
+ handleSubmit,
+ message: messageTranslationKey != null ? t(messageTranslationKey) : null
+ }
+}
diff --git a/hooks/useFormState.tsx b/hooks/useFormState.ts
similarity index 100%
rename from hooks/useFormState.tsx
rename to hooks/useFormState.ts
diff --git a/i18n.json b/i18n.json
index b2e0b17..e1a9a74 100644
--- a/i18n.json
+++ b/i18n.json
@@ -10,6 +10,9 @@
"/authentication/reset-password": ["authentication", "errors"],
"/authentication/signup": ["authentication", "errors"],
"/authentication/signin": ["authentication", "errors"],
- "/application/users/[userId]": ["application"]
+ "/application/users/[userId]": ["application", "errors"],
+ "/application/guilds/create": ["application", "errors"],
+ "/application/guilds/join": ["application", "errors"],
+ "/application": ["application", "errors"]
}
}
diff --git a/locales/en/application.json b/locales/en/application.json
index 637074e..84f0ec5 100644
--- a/locales/en/application.json
+++ b/locales/en/application.json
@@ -1,3 +1,5 @@
{
- "website": "Website"
+ "website": "Website",
+ "create": "Create",
+ "create-a-guild": "Create a Guild"
}
diff --git a/locales/en/authentication.json b/locales/en/authentication.json
index 56909e7..7febab8 100644
--- a/locales/en/authentication.json
+++ b/locales/en/authentication.json
@@ -1,7 +1,6 @@
{
"or": "OR",
"password": "Password",
- "name": "Name",
"already-have-an-account": "Already have an account?",
"dont-have-an-account": "Don't have an account?",
"submit": "Submit",
diff --git a/locales/en/common.json b/locales/en/common.json
index d5bd8e4..95b71f3 100644
--- a/locales/en/common.json
+++ b/locales/en/common.json
@@ -2,5 +2,6 @@
"english": "English",
"french": "French",
"all-rights-reserved": "All rights reserved",
- "description": "Stay close with your friends and communities, talk, chat, collaborate, share, and have fun."
+ "description": "Stay close with your friends and communities, talk, chat, collaborate, share, and have fun.",
+ "name": "Name"
}
diff --git a/locales/fr/application.json b/locales/fr/application.json
index ca95713..c1af9f5 100644
--- a/locales/fr/application.json
+++ b/locales/fr/application.json
@@ -1,3 +1,5 @@
{
- "website": "Site web"
+ "website": "Site web",
+ "create": "Crée",
+ "create-a-guild": "Crée une Guilde"
}
diff --git a/locales/fr/authentication.json b/locales/fr/authentication.json
index 4fac5ad..9db8638 100644
--- a/locales/fr/authentication.json
+++ b/locales/fr/authentication.json
@@ -1,7 +1,6 @@
{
"or": "OU",
"password": "Mot de passe",
- "name": "Nom",
"already-have-an-account": "Vous avez déjà un compte ?",
"dont-have-an-account": "Vous n'avez pas de compte ?",
"submit": "Soumettre",
diff --git a/locales/fr/common.json b/locales/fr/common.json
index a5980d4..0c3eae3 100644
--- a/locales/fr/common.json
+++ b/locales/fr/common.json
@@ -2,5 +2,6 @@
"english": "Anglais",
"french": "Français",
"all-rights-reserved": "Tous droits réservés",
- "description": "Restez proche de vos amis et de vos communautés, parlez, collaborez, partagez et amusez-vous."
+ "description": "Restez proche de vos amis et de vos communautés, parlez, collaborez, partagez et amusez-vous.",
+ "name": "Nom"
}
diff --git a/models/Channel.ts b/models/Channel.ts
index eb21334..4246744 100644
--- a/models/Channel.ts
+++ b/models/Channel.ts
@@ -6,7 +6,7 @@ export const types = [Type.Literal('text')]
export const channelSchema = {
id,
- name: Type.String({ maxLength: 255 }),
+ name: Type.String({ minLength: 1, maxLength: 20 }),
createdAt: date.createdAt,
updatedAt: date.updatedAt,
guildId: id
diff --git a/models/Guild.ts b/models/Guild.ts
index ee821fd..e1b6522 100644
--- a/models/Guild.ts
+++ b/models/Guild.ts
@@ -1,12 +1,24 @@
-import { Type } from '@sinclair/typebox'
+import { Type, Static } from '@sinclair/typebox'
+import { channelSchema } from './Channel'
+import { memberSchema } from './Member'
import { date, id } from './utils'
export const guildSchema = {
id,
- name: Type.String({ minLength: 3, maxLength: 30 }),
- icon: Type.String({ format: 'uri-reference' }),
- description: Type.String({ maxLength: 160 }),
+ name: Type.String({ minLength: 1, maxLength: 30 }),
+ icon: Type.Union([Type.String({ format: 'uri-reference' }), Type.Null()]),
+ description: Type.Union([Type.String({ maxLength: 160 }), Type.Null()]),
createdAt: date.createdAt,
updatedAt: date.updatedAt
}
+
+export const guildCompleteSchema = {
+ ...guildSchema,
+ channels: Type.Array(Type.Object(channelSchema)),
+ members: Type.Array(Type.Object(memberSchema))
+}
+
+export const guildCompleteObjectSchema = Type.Object(guildCompleteSchema)
+
+export type GuildComplete = Static
diff --git a/models/Message.ts b/models/Message.ts
index e45b15c..c8a0d7a 100644
--- a/models/Message.ts
+++ b/models/Message.ts
@@ -6,10 +6,13 @@ export const types = [Type.Literal('text'), Type.Literal('file')]
export const messageSchema = {
id,
- value: Type.String(),
+ value: Type.String({
+ minLength: 1,
+ maxLength: 20_000
+ }),
type: Type.Union(types, { default: 'text' }),
mimetype: Type.String({
- maxLength: 255,
+ maxLength: 127,
default: 'text/plain',
format: 'mimetype'
}),
diff --git a/models/User.ts b/models/User.ts
index 812837e..4884aa4 100644
--- a/models/User.ts
+++ b/models/User.ts
@@ -7,11 +7,11 @@ import { date, id } from './utils'
export const userSchema = {
id,
name: Type.String({ minLength: 1, maxLength: 30 }),
- email: Type.String({ minLength: 1, maxLength: 255, format: 'email' }),
+ email: Type.String({ minLength: 1, maxLength: 254, format: 'email' }),
password: Type.String({ minLength: 1 }),
- logo: Type.String({ format: 'uri-reference' }),
- status: Type.String({ maxLength: 255 }),
- biography: Type.String(),
+ logo: Type.Union([Type.String({ format: 'uri-reference' }), Type.Null()]),
+ status: Type.Union([Type.String({ maxLength: 50 }), Type.Null()]),
+ biography: Type.Union([Type.String({ maxLength: 160 }), Type.Null()]),
website: Type.String({ maxLength: 255, format: 'uri-reference' }),
isConfirmed: Type.Boolean({ default: false }),
temporaryToken: Type.String(),
@@ -20,32 +20,34 @@ export const userSchema = {
updatedAt: date.updatedAt
}
-const userSchemaWithSettings = {
- ...userSchema,
- settings: Type.Object(userSettingsSchema)
+export const userObjectSchema = Type.Object(userSchema)
+
+export const userPublicWithoutSettingsSchema = {
+ id,
+ name: userSchema.name,
+ email: Type.Union([userSchema.email, Type.Null()]),
+ logo: userSchema.logo,
+ status: userSchema.status,
+ biography: userSchema.biography,
+ website: Type.Union([userSchema.website, Type.Null()]),
+ isConfirmed: userSchema.isConfirmed,
+ createdAt: date.createdAt,
+ updatedAt: date.updatedAt
}
export const userPublicSchema = {
- id,
- name: userSchema.name,
- email: Type.Optional(userSchema.email),
- logo: Type.Optional(userSchema.logo),
- status: Type.Optional(userSchema.status),
- biography: Type.Optional(userSchema.biography),
- website: Type.Optional(userSchema.website),
- isConfirmed: userSchema.isConfirmed,
- createdAt: date.createdAt,
- updatedAt: date.updatedAt,
- settings: Type.Optional(Type.Object(userSettingsSchema))
+ ...userPublicWithoutSettingsSchema,
+ settings: Type.Object(userSettingsSchema)
}
export const userPublicObjectSchema = Type.Object(userPublicSchema)
export const userCurrentSchema = Type.Object({
- ...userSchemaWithSettings,
+ ...userPublicSchema,
currentStrategy: Type.Union([...strategiesTypebox]),
strategies: Type.Array(Type.Union([...strategiesTypebox]))
})
+export type User = Static
export type UserPublic = Static
export type UserCurrent = Static
diff --git a/next.config.js b/next.config.js
index 4cdf79a..c22e29c 100644
--- a/next.config.js
+++ b/next.config.js
@@ -6,6 +6,12 @@ module.exports = nextTranslate(
pwa: {
disable: process.env.NODE_ENV !== 'production',
dest: 'public'
+ },
+ images: {
+ domains: [
+ 'api.thream.divlo.fr',
+ ...(process.env.NODE_ENV === 'development' ? ['localhost'] : [])
+ ]
}
})
)
diff --git a/package-lock.json b/package-lock.json
index 7690617..9591cdc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"@sinclair/typebox": "0.20.5",
"ajv": "8.6.3",
"ajv-formats": "2.1.1",
+ "axios": "0.23.0",
"classnames": "2.3.1",
"date-and-time": "2.0.1",
"next": "11.1.2",
@@ -8388,12 +8389,11 @@
}
},
"node_modules/axios": {
- "version": "0.21.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
- "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
- "dev": true,
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.23.0.tgz",
+ "integrity": "sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==",
"dependencies": {
- "follow-redirects": "^1.14.0"
+ "follow-redirects": "^1.14.4"
}
},
"node_modules/axobject-query": {
@@ -16214,7 +16214,6 @@
"version": "1.14.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
"integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
- "dev": true,
"funding": [
{
"type": "individual",
@@ -37731,6 +37730,15 @@
"node": ">=10.0.0"
}
},
+ "node_modules/wait-on/node_modules/axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "dev": true,
+ "dependencies": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
"node_modules/wait-on/node_modules/rxjs": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
@@ -45698,12 +45706,11 @@
"dev": true
},
"axios": {
- "version": "0.21.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
- "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
- "dev": true,
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.23.0.tgz",
+ "integrity": "sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==",
"requires": {
- "follow-redirects": "^1.14.0"
+ "follow-redirects": "^1.14.4"
}
},
"axobject-query": {
@@ -51976,8 +51983,7 @@
"follow-redirects": {
"version": "1.14.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
- "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
- "dev": true
+ "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g=="
},
"for-in": {
"version": "1.0.2",
@@ -68666,6 +68672,15 @@
"rxjs": "^7.1.0"
},
"dependencies": {
+ "axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "dev": true,
+ "requires": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
"rxjs": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
diff --git a/package.json b/package.json
index 966e90a..a0e7661 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"@sinclair/typebox": "0.20.5",
"ajv": "8.6.3",
"ajv-formats": "2.1.1",
+ "axios": "0.23.0",
"classnames": "2.3.1",
"date-and-time": "2.0.1",
"next": "11.1.2",
diff --git a/pages/application/guilds/create.tsx b/pages/application/guilds/create.tsx
index 60182aa..663bd45 100644
--- a/pages/application/guilds/create.tsx
+++ b/pages/application/guilds/create.tsx
@@ -1,77 +1,19 @@
-import Image from 'next/image'
-import { Form } from 'react-component-form'
-import TextareaAutosize from 'react-textarea-autosize'
-
import { Head } from 'components/Head'
import { Application } from 'components/Application'
-import { Input } from 'components/design/Input'
-import { Main } from 'components/design/Main'
-import { Button } from 'components/design/Button'
-import { FormState } from 'components/design/FormState'
+
import {
authenticationFromServerSide,
AuthenticationProvider,
PagePropsWithAuthentication
} from 'utils/authentication'
+import { CreateGuild } from 'components/Application/CreateGuild'
-const CreateGuild: React.FC = (props) => {
+const CreateGuildPage: React.FC = (props) => {
return (
-
-
-
+
)
@@ -81,4 +23,4 @@ export const getServerSideProps = authenticationFromServerSide({
shouldBeAuthenticated: true
})
-export default CreateGuild
+export default CreateGuildPage
diff --git a/pages/application/users/[userId].tsx b/pages/application/users/[userId].tsx
index 3245364..5ca68a9 100644
--- a/pages/application/users/[userId].tsx
+++ b/pages/application/users/[userId].tsx
@@ -5,8 +5,7 @@ import {
AuthenticationProvider,
PagePropsWithAuthentication
} from 'utils/authentication'
-
-import { UserProfile } from 'components/UserProfile'
+import { UserProfile } from 'components/Application/UserProfile'
const UserProfilePage: React.FC = (props) => {
return (
diff --git a/pages/authentication/forgot-password.tsx b/pages/authentication/forgot-password.tsx
index 255a271..7344a30 100644
--- a/pages/authentication/forgot-password.tsx
+++ b/pages/authentication/forgot-password.tsx
@@ -1,10 +1,7 @@
-import { useState, useMemo } from 'react'
import Link from 'next/link'
import { AuthenticationForm } from 'components/Authentication'
import useTranslation from 'next-translate/useTranslation'
-import { HandleForm } from 'react-component-form'
import axios from 'axios'
-import { Type } from '@sinclair/typebox'
import { Head } from 'components/Head'
import { Header } from 'components/Header'
@@ -13,54 +10,40 @@ import { Footer, FooterProps } from 'components/Footer'
import { Input } from 'components/design/Input'
import { Button } from 'components/design/Button'
import { FormState } from 'components/design/FormState'
-import { useFormState } from 'hooks/useFormState'
import { authenticationFromServerSide } from 'utils/authentication'
import { ScrollableBody } from 'components/ScrollableBody'
+import { userSchema } from 'models/User'
import { api } from 'utils/api'
-import { userSchema } from '../../models/User'
-import { ajv } from '../../utils/ajv'
+import { HandleSubmitCallback, useForm } from 'hooks/useForm'
const ForgotPassword: React.FC = (props) => {
const { t } = useTranslation()
const { version } = props
- const [formState, setFormState] = useFormState()
- const [messageTranslationKey, setMessageTranslationKey] = useState<
- string | undefined
- >(undefined)
- const validateSchema = useMemo(() => {
- return Type.Object({
- email: userSchema.email
- })
- }, [])
+ const { formState, message, errors, getErrorTranslation, handleSubmit } =
+ useForm({ validateSchemaObject: { email: userSchema.email } })
- const validate = useMemo(() => {
- return ajv.compile(validateSchema)
- }, [validateSchema])
-
- const handleSubmit: HandleForm = async (formData, formElement) => {
- const isValid = validate(formData)
- if (!isValid) {
- setFormState('error')
- setMessageTranslationKey('errors:email')
- } else {
- setFormState('loading')
- try {
- await api.post(
- `/users/reset-password?redirectURI=${window.location.origin}/authentication/reset-password`,
- formData
- )
- formElement.reset()
- setFormState('success')
- setMessageTranslationKey('authentication:success-forgot-password')
- } catch (error) {
- setFormState('error')
- if (axios.isAxiosError(error) && error.response?.status === 400) {
- setMessageTranslationKey('errors:email')
- } else {
- setMessageTranslationKey('errors:server-error')
+ const onSubmit: HandleSubmitCallback = async (formData) => {
+ try {
+ await api.post(
+ `/users/reset-password?redirectURI=${window.location.origin}/authentication/reset-password`,
+ formData
+ )
+ return {
+ type: 'success',
+ value: 'authentication:success-forgot-password'
+ }
+ } catch (error) {
+ if (axios.isAxiosError(error) && error.response?.status === 400) {
+ return {
+ type: 'error',
+ value: 'errors:email'
}
}
+ return {
+ type: 'error',
+ value: 'errors:server-error'
+ }
}
}
@@ -69,7 +52,7 @@ const ForgotPassword: React.FC = (props) => {
-
+
diff --git a/pages/authentication/reset-password.tsx b/pages/authentication/reset-password.tsx
index 6aabc68..8d21710 100644
--- a/pages/authentication/reset-password.tsx
+++ b/pages/authentication/reset-password.tsx
@@ -1,9 +1,6 @@
-import { useState, useMemo } from 'react'
import { useRouter } from 'next/router'
import useTranslation from 'next-translate/useTranslation'
-import { HandleForm } from 'react-component-form'
import axios from 'axios'
-import { Type } from '@sinclair/typebox'
import { Head } from 'components/Head'
import { Header } from 'components/Header'
@@ -12,54 +9,40 @@ import { Footer, FooterProps } from 'components/Footer'
import { Input } from 'components/design/Input'
import { Button } from 'components/design/Button'
import { FormState } from 'components/design/FormState'
-import { useFormState } from 'hooks/useFormState'
import { authenticationFromServerSide } from 'utils/authentication'
import { AuthenticationForm } from 'components/Authentication'
import { ScrollableBody } from 'components/ScrollableBody/ScrollableBody'
import { api } from 'utils/api'
import { userSchema } from '../../models/User'
-import { ajv } from '../../utils/ajv'
+import { HandleSubmitCallback, useForm } from 'hooks/useForm'
const ResetPassword: React.FC = (props) => {
const { t } = useTranslation()
const router = useRouter()
const { version } = props
- const [formState, setFormState] = useFormState()
- const [messageTranslationKey, setMessageTranslationKey] = useState<
- string | undefined
- >(undefined)
- const validateSchema = useMemo(() => {
- return Type.Object({
- password: userSchema.password
- })
- }, [])
+ const { formState, message, errors, getErrorTranslation, handleSubmit } =
+ useForm({ validateSchemaObject: { password: userSchema.password } })
- const validate = useMemo(() => {
- return ajv.compile(validateSchema)
- }, [validateSchema])
-
- const handleSubmit: HandleForm = async (formData, formElement) => {
- const isValid = validate(formData)
- if (!isValid) {
- setFormState('error')
- setMessageTranslationKey('errors:invalid')
- } else {
- setFormState('loading')
- try {
- await api.put(`/users/reset-password`, {
- ...formData,
- temporaryToken: router.query.temporaryToken
- })
- await router.push('/authentication/signin')
- } catch (error) {
- setFormState('error')
- if (axios.isAxiosError(error) && error.response?.status === 400) {
- setMessageTranslationKey('errors:invalid')
- } else {
- setMessageTranslationKey('errors:server-error')
+ const onSubmit: HandleSubmitCallback = async (formData) => {
+ try {
+ await api.put(`/users/reset-password`, {
+ ...formData,
+ temporaryToken: router.query.temporaryToken
+ })
+ await router.push('/authentication/signin')
+ return null
+ } catch (error) {
+ if (axios.isAxiosError(error) && error.response?.status === 400) {
+ return {
+ type: 'error',
+ value: 'errors:invalid'
}
}
+ return {
+ type: 'error',
+ value: 'errors:server-error'
+ }
}
}
@@ -68,7 +51,7 @@ const ResetPassword: React.FC = (props) => {
-
+
= (props) => {
id='message'
state={formState}
message={
- messageTranslationKey != null ? t(messageTranslationKey) : null
+ message != null ? message : getErrorTranslation(errors.password)
}
/>
diff --git a/public/images/data/divlo.png b/public/images/data/divlo.png
deleted file mode 100644
index 06bb3472830c2242e2223342b9f84b89711d3f37..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 41784
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
uoGMfTsD$CB%e
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