diff --git a/src/components/Discours/Subscribe.module.scss b/src/components/Discours/Subscribe.module.scss index 410e53e9..dbdf22f5 100644 --- a/src/components/Discours/Subscribe.module.scss +++ b/src/components/Discours/Subscribe.module.scss @@ -1,47 +1,77 @@ -.subscribeForm { +@mixin input-placeholder-overflow($direction: 'down') { + @if $direction == 'down' { + @media (max-width: 1410px) { + @content; + } + } @else if $direction == 'up' { + @media (min-width: 1411px) { + @content; + } + } @else { + @error "Unknown direction #{$direction}."; + } +} + +.form { + display: flex; + flex-direction: column; + + @include input-placeholder-overflow(down) { + margin-bottom: 2.4rem; + } +} + +.controls { display: flex; width: 100%; - @include media-breakpoint-down(md) { - margin-bottom: 2.4rem; - } - - @include media-breakpoint-between(md, xl) { + @include input-placeholder-overflow(down) { flex-direction: column; } - input { + .input { @include font-size(2rem); background: none; - border: none; - border-bottom: 1px solid; color: #fff; font-family: inherit; margin: 0; overflow: hidden; text-overflow: ellipsis; - padding: 0.2em 0.5em 0.3em 0; + padding: 0.2em 0.5em 0.2em 0.5em; width: 100%; + outline: none; + border: 1px solid #fff; + border-radius: 0; + height: 4rem; + + @include input-placeholder-overflow(up) { + border-right: none; + } + + @include input-placeholder-overflow(down) { + border-bottom: none; + } &::placeholder { - color: #fff; + color: #858585; } } - a { - @include font-size(1.5rem); - - align-items: center; - background: #fff; - border: none; - color: #000; - display: flex; - padding: 0 0.5em; - } - .button { border-radius: 0; - margin: 0; + flex-shrink: 0; + + @include input-placeholder-overflow(down) { + width: 100%; + } } } + +.error { + position: relative; + top: 4px; + font-size: 12px; + line-height: 16px; + color: #d00820; +} diff --git a/src/components/Discours/Subscribe.tsx b/src/components/Discours/Subscribe.tsx index 56ff8141..32a9e5c8 100644 --- a/src/components/Discours/Subscribe.tsx +++ b/src/components/Discours/Subscribe.tsx @@ -1,14 +1,43 @@ -import { createSignal, Show } from 'solid-js' -import styles from './Subscribe.module.scss' +import { createSignal, JSX, Show } from 'solid-js' -import { clsx } from 'clsx' import { useLocalize } from '../../context/localize' +import { isValidEmail } from '../../utils/validators' +import { Button } from '../_shared/Button' + +import styles from './Subscribe.module.scss' export default () => { const { t } = useLocalize() - let emailElement: HTMLInputElement | undefined + const [title, setTitle] = createSignal('') - const subscribe = async () => { + const [email, setEmail] = createSignal('') + const [emailError, setEmailError] = createSignal(null) + + const validate = (): boolean => { + if (!email()) { + setEmailError(t('Please enter email')) + return false + } + + if (!isValidEmail(email())) { + setEmailError(t('Please check your email address')) + return false + } + + setEmailError(null) + return true + } + + const handleInput: JSX.ChangeEventHandlerUnion = (event) => { + setEmailError(null) + setEmail(event.target.value) + } + + const handleSubmit = async (event: SubmitEvent) => { + event.preventDefault() + + if (!validate()) return + setTitle(t('...subscribing')) const requestOptions = { @@ -16,26 +45,42 @@ export default () => { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - email: emailElement?.value - }) + body: JSON.stringify({ email: email() }) } - const r = await fetch('/api/newsletter', requestOptions) - setTitle(r.ok ? t('You are subscribed') : '') + const response = await fetch('/api/newsletter', requestOptions) + + if (response.ok) { + setTitle(t('You are subscribed')) + } else { + if (response.status === 400) { + setEmailError(t('Please check your email address')) + } else { + setEmailError(t('Something went wrong, please try again')) + } + + setTitle('') + } } return ( -
+
- - +
+ +
+ +
{emailError()}
+
-
+ ) } diff --git a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx index 91badbc7..ca76687d 100644 --- a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx +++ b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx @@ -4,10 +4,10 @@ import { createSignal, JSX, Show } from 'solid-js' import { useRouter } from '../../../stores/router' import { email, setEmail } from './sharedLogic' import type { AuthModalSearchParams } from './types' -import { isValidEmail } from './validators' import { ApiError } from '../../../utils/apiClient' import { signSendLink } from '../../../stores/auth' import { useLocalize } from '../../../context/localize' +import { isValidEmail } from '../../../utils/validators' type FormFields = { email: string diff --git a/src/components/Nav/AuthModal/LoginForm.tsx b/src/components/Nav/AuthModal/LoginForm.tsx index 079917c9..d15c8700 100644 --- a/src/components/Nav/AuthModal/LoginForm.tsx +++ b/src/components/Nav/AuthModal/LoginForm.tsx @@ -3,13 +3,13 @@ import { clsx } from 'clsx' import { SocialProviders } from './SocialProviders' import { ApiError } from '../../../utils/apiClient' import { createSignal, Show } from 'solid-js' -import { isValidEmail } from './validators' import { email, setEmail } from './sharedLogic' import { useRouter } from '../../../stores/router' import type { AuthModalSearchParams } from './types' import { hideModal } from '../../../stores/ui' import { useSession } from '../../../context/session' import { signSendLink } from '../../../stores/auth' +import { isValidEmail } from '../../../utils/validators' import { useSnackbar } from '../../../context/snackbar' import { useLocalize } from '../../../context/localize' diff --git a/src/components/Nav/AuthModal/RegisterForm.tsx b/src/components/Nav/AuthModal/RegisterForm.tsx index 98702bfe..8a5cf7c3 100644 --- a/src/components/Nav/AuthModal/RegisterForm.tsx +++ b/src/components/Nav/AuthModal/RegisterForm.tsx @@ -3,7 +3,6 @@ import type { JSX } from 'solid-js' import styles from './AuthModal.module.scss' import { clsx } from 'clsx' import { SocialProviders } from './SocialProviders' -import { isValidEmail } from './validators' import { ApiError } from '../../../utils/apiClient' import { email, setEmail } from './sharedLogic' import { useRouter } from '../../../stores/router' @@ -12,6 +11,7 @@ import { hideModal } from '../../../stores/ui' import { checkEmail, useEmailChecks } from '../../../stores/emailChecks' import { register } from '../../../stores/auth' import { useLocalize } from '../../../context/localize' +import { isValidEmail } from '../../../utils/validators' type FormFields = { name: string diff --git a/src/components/_shared/Button/Button.module.scss b/src/components/_shared/Button/Button.module.scss index e10965b5..2913dc56 100644 --- a/src/components/_shared/Button/Button.module.scss +++ b/src/components/_shared/Button/Button.module.scss @@ -20,15 +20,13 @@ } &.secondary { + border: 1px solid #f7f7f7; background: #f7f7f7; color: #141414; &:hover { - background: #e8e8e8; - } - - &:active { - background: #ccc; + background: #000; + color: #fff; } } diff --git a/src/components/Nav/AuthModal/validators.ts b/src/utils/validators.ts similarity index 55% rename from src/components/Nav/AuthModal/validators.ts rename to src/utils/validators.ts index a4950dff..564a964e 100644 --- a/src/components/Nav/AuthModal/validators.ts +++ b/src/utils/validators.ts @@ -3,5 +3,5 @@ export const isValidEmail = (email: string) => { return false } - return email.includes('@') && email.includes('.') && email.length > 5 + return /^[\w%+.-]+@[\d.a-z-]+\.[a-z]{2,}$/i.test(email) }