Import source: src/components/CenterPanel/forms/EmailForm
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
import { useQR } from '../../../context/QRContext';
|
||||||
|
import { TextareaInput } from '../../ui/TextareaInput';
|
||||||
|
|
||||||
|
function isValidEmail(v: string) {
|
||||||
|
if (!v.trim()) return true;
|
||||||
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ValidInputProps {
|
||||||
|
label: string; optional?: boolean; value: string;
|
||||||
|
onChange: (v: string) => void; placeholder?: string; type?: string;
|
||||||
|
validate?: (v: string) => boolean; errorMsg?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ValidatedInput({ label, optional, value, onChange, placeholder, type = 'text', validate, errorMsg }: ValidInputProps) {
|
||||||
|
const valid = validate ? validate(value) : true;
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<label className="text-[15px] font-semibold flex items-center gap-1.5" style={{ color: 'var(--text-primary)' }}>
|
||||||
|
{label}
|
||||||
|
{optional && <span className="text-[13px] font-normal" style={{ color: 'var(--text-muted)' }}>(optional)</span>}
|
||||||
|
</label>
|
||||||
|
<input type={type} value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder}
|
||||||
|
className="h-12 px-4 rounded-[11px] text-[14px] outline-none transition-all"
|
||||||
|
style={{ background: 'var(--bg-input)', border: `1px solid ${!valid ? '#ef4444' : 'var(--border-sub)'}`, color: 'var(--text-primary)' }}
|
||||||
|
onFocus={e => { if (valid) { e.currentTarget.style.borderColor = '#7C6FE0'; e.currentTarget.style.boxShadow = '0 0 0 3px rgba(124,111,224,0.12)'; }}}
|
||||||
|
onBlur={e => { e.currentTarget.style.borderColor = valid ? 'var(--border-sub)' : '#ef4444'; e.currentTarget.style.boxShadow = 'none'; }}
|
||||||
|
/>
|
||||||
|
{!valid && <p className="text-[12px]" style={{ color: '#ef4444' }}>{errorMsg}</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EmailForm() {
|
||||||
|
const { state, dispatch } = useQR();
|
||||||
|
const { emailAddress, subject, message } = state.formData.email;
|
||||||
|
const set = (field: string, value: string) =>
|
||||||
|
dispatch({ type: 'SET_FORM_FIELD', qrType: 'email', field, value });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<ValidatedInput label="Email Address" value={emailAddress} onChange={v => set('emailAddress', v)}
|
||||||
|
placeholder="email@example.com" type="email"
|
||||||
|
validate={isValidEmail} errorMsg="Enter a valid email address" />
|
||||||
|
<ValidatedInput label="Subject" optional value={subject} onChange={v => set('subject', v)} placeholder="Email subject" />
|
||||||
|
<TextareaInput label="Message" optional value={message} onChange={v => set('message', v)} placeholder="Email body..." />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user