feat: wip on client form
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
header {
|
||||
background-color: #181818;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
box-shadow: 0 8px 12px #000000b0;
|
||||
}
|
||||
|
||||
header img {
|
||||
aspect-ratio: 1;
|
||||
border: 2px solid #b39cd0;
|
||||
border-radius: 0.25rem;
|
||||
width: 12rem;
|
||||
}
|
||||
|
||||
form {
|
||||
background-color: #181818;
|
||||
border-radius: 0.25rem;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
width: 22.5rem;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
box-shadow: 0 4px 8px #0000001a;
|
||||
}
|
||||
|
||||
form .group {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
form label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
form input {
|
||||
color: #e4e4e4;
|
||||
background-color: #282828;
|
||||
border: 1px solid #444;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
form input[type='number']::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form input[type='number']::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form input[type='number'] {
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ff6b6b;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
form button {
|
||||
color: #fff;
|
||||
background-color: #b39cd0;
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem;
|
||||
font-weight: 700;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,118 @@
|
||||
import '@/App.css';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
// TODO: Maybe be good to require
|
||||
// the user provide some sort of
|
||||
// identifier so we can display
|
||||
// that as part of the feed
|
||||
|
||||
function App() {
|
||||
const [amount, setAmount] = useState<number | ''>('');
|
||||
const [email, setEmail] = useState<string>('');
|
||||
const [errors, setErrors] = useState<{ amount?: string; email?: string }>({});
|
||||
|
||||
const amountInputRef = useRef<HTMLInputElement>(null);
|
||||
const emailInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
function handleAmountInput(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
errors.amount = undefined;
|
||||
const value = parseInt(event.target.value);
|
||||
setAmount(isNaN(value) ? '' : value);
|
||||
}
|
||||
|
||||
function handleEmailInput(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
errors.email = undefined;
|
||||
setEmail(event.target.value);
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
const newErrors: { amount?: string; email?: string } = {};
|
||||
|
||||
if (amount === '' || amount <= 0) {
|
||||
newErrors.amount = 'Please enter a valid amount greater than 0.';
|
||||
}
|
||||
|
||||
if (email.trim() !== '' && emailInputRef.current?.validity.typeMismatch) {
|
||||
newErrors.email = 'Please enter a valid email address.';
|
||||
}
|
||||
|
||||
setErrors(newErrors);
|
||||
|
||||
const isValid = Object.keys(newErrors).length === 0;
|
||||
|
||||
if (isValid === false) {
|
||||
if (newErrors.amount) {
|
||||
amountInputRef.current?.focus();
|
||||
} else if (newErrors.email) {
|
||||
emailInputRef.current?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
|
||||
const isValid = validateForm();
|
||||
|
||||
if (isValid === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We will stop displaying our form
|
||||
// and we will initialize the stripe embedded
|
||||
// elements and pass along the amount and email
|
||||
alert(`Form is valid! Amount: ${amount}, Email: ${email}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>Hello World</div>
|
||||
<>
|
||||
<header>
|
||||
<img src="https://github.com/StevanFreeborn.png" alt="Logo" />
|
||||
<p>Some information about me</p>
|
||||
</header>
|
||||
<main>
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
noValidate
|
||||
>
|
||||
<div className='group'>
|
||||
<label htmlFor='amount'>Amount</label>
|
||||
<input
|
||||
ref={amountInputRef}
|
||||
id='amount'
|
||||
type='number'
|
||||
min={1}
|
||||
aria-describedby='amountErrorMessage'
|
||||
aria-invalid={errors.amount ? 'true' : 'false'}
|
||||
value={amount}
|
||||
onInput={handleAmountInput}
|
||||
/>
|
||||
<span className='error-message'>{errors.amount}</span>
|
||||
</div>
|
||||
<div className='group'>
|
||||
<label htmlFor='email'>Email</label>
|
||||
<input
|
||||
ref={emailInputRef}
|
||||
id='email'
|
||||
type='email'
|
||||
aria-describedby='emailErrorMessage'
|
||||
aria-invalid={errors.email ? 'true' : 'false'}
|
||||
value={email}
|
||||
onInput={handleEmailInput}
|
||||
/>
|
||||
<span
|
||||
id='emailErrorMessage'
|
||||
className='error-message'
|
||||
>
|
||||
{errors.email}
|
||||
</span>
|
||||
</div>
|
||||
<button type='submit'>Buy</button>
|
||||
</form>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
@font-face {
|
||||
font-family: 'CaskaydiaCove NFM';
|
||||
src: url('/CaskaydiaCoveNFM-Regular.eot');
|
||||
src: url('/CaskaydiaCoveNFM-Regular.eot?#iefix') format('embedded-opentype'),
|
||||
url('/CaskaydiaCoveNFM-Regular.woff2') format('woff2'),
|
||||
url('/CaskaydiaCoveNFM-Regular.woff') format('woff'),
|
||||
url('/CaskaydiaCoveNFM-Regular.svg#CaskaydiaCoveNFM-Regular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* CSS Reset */
|
||||
|
||||
* {
|
||||
@@ -16,6 +28,9 @@ button {
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -40,6 +55,23 @@ table {
|
||||
/* Base Styles */
|
||||
|
||||
:root {
|
||||
--bg-color: #323232;
|
||||
--text-color: #E4E4E4;
|
||||
|
||||
font-size: 16px;
|
||||
font-family: 'CaskaydiaCove NFM', monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 1rem;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user