stuff changed:

- ui has been made 'kinda better' (after making it worse for a while lol
- ESP rfid readers are now supported [ill upload the code for them in another repo later]
- admin system has been secured a bit better and seems to be working well
This commit is contained in:
2026-05-08 20:46:58 +01:00
parent 1a0b4dc25d
commit d024bf7fa3
32 changed files with 7480 additions and 2740 deletions
+157 -135
View File
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import { authService, RegisterData } from '../services/membershipService';
const Register: React.FC = () => {
@@ -67,142 +67,164 @@ const Register: React.FC = () => {
};
return (
<div className="auth-container">
<div className="auth-card">
<h2>Create Your Account</h2>
<p style={{ textAlign: 'center', marginBottom: '24px', color: '#666' }}>
Join Swansea Airport Stakeholders Alliance
</p>
{error && <div className="alert alert-error">{error}</div>}
<form onSubmit={handleSubmit} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '40px', maxWidth: '900px', margin: '0 auto' }}>
{/* Left Column - Personal Information */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<div className="form-group">
<label htmlFor="first_name">First Name *</label>
<input
type="text"
id="first_name"
name="first_name"
value={formData.first_name}
onChange={handleChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="last_name">Last Name *</label>
<input
type="text"
id="last_name"
name="last_name"
value={formData.last_name}
onChange={handleChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="email">Email Address *</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="password">Password *</label>
<input
type="password"
id="password"
name="password"
value={formData.password}
onChange={handlePasswordChange}
minLength={8}
required
/>
<small style={{ color: '#666', fontSize: '12px' }}>
Minimum 8 characters
</small>
</div>
<div className="form-group">
<label htmlFor="confirmPassword">Confirm Password *</label>
<input
type="password"
id="confirmPassword"
name="confirmPassword"
value={confirmPassword}
onChange={handlePasswordChange}
minLength={8}
required
style={{
borderColor: confirmPassword && !passwordsMatch ? '#dc3545' : confirmPassword && passwordsMatch ? '#28a745' : undefined
}}
/>
{confirmPassword && (
<small style={{
color: passwordsMatch ? '#28a745' : '#dc3545',
fontSize: '12px'
}}>
{passwordsMatch ? '✓ Passwords match' : '✗ Passwords do not match'}
</small>
)}
{!confirmPassword && (
<small style={{ color: '#666', fontSize: '12px' }}>
Re-enter your password
</small>
)}
</div>
<div className="auth-shell">
<header className="auth-topbar">
<div className="portal-brand">
<div className="portal-mark">S</div>
<div className="portal-brand-text">
<h1>SASA Member Portal</h1>
<div className="portal-subtitle">Membership registration and profile setup</div>
</div>
{/* Right Column - Contact Information */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<div className="form-group">
<label htmlFor="phone">Phone (optional)</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="address">Address (optional)</label>
<textarea
id="address"
name="address"
value={formData.address}
onChange={handleChange}
rows={3}
/>
</div>
</div>
{/* Submit Button - Full Width */}
<div style={{ gridColumn: '1 / -1', marginTop: '8px' }}>
<button
type="submit"
className="btn btn-primary"
disabled={loading}
style={{ width: '100%' }}
>
{loading ? 'Creating Account...' : 'Create Account & Sign In'}
</button>
</div>
</form>
<div className="form-footer">
Already have an account? <a href="/login">Log in</a>
</div>
</div>
</header>
<main className="auth-container auth-container-wide">
<section className="auth-welcome-card">
<div className="auth-kicker">New Membership</div>
<h2>Join the SASA community</h2>
<p>
Create your account to manage your membership, respond to events, and keep your contact details up to date.
</p>
<div className="auth-feature-list">
<div className="auth-feature-item">Straightforward onboarding with automatic sign-in</div>
<div className="auth-feature-item">Membership tiers, payments, and event RSVPs in one place</div>
<div className="auth-feature-item">A separate admin workspace for staff users after login</div>
</div>
</section>
<section className="auth-card auth-card-wide">
<div className="auth-card-head">
<h2>Create Account</h2>
<span>Step 1 of 1</span>
</div>
<div className="auth-card-body">
<p className="auth-card-copy">
Complete the essentials below. You can add or update the rest of your profile later from your dashboard.
</p>
{error && <div className="alert alert-error">{error}</div>}
<form onSubmit={handleSubmit} className="auth-form-grid">
<div className="form-group">
<label htmlFor="first_name">First Name *</label>
<input
type="text"
id="first_name"
name="first_name"
value={formData.first_name}
onChange={handleChange}
autoComplete="given-name"
required
/>
</div>
<div className="form-group">
<label htmlFor="last_name">Last Name *</label>
<input
type="text"
id="last_name"
name="last_name"
value={formData.last_name}
onChange={handleChange}
autoComplete="family-name"
required
/>
</div>
<div className="form-group">
<label htmlFor="email">Email Address *</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
autoComplete="email"
required
/>
</div>
<div className="form-group">
<label htmlFor="phone">Phone</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
autoComplete="tel"
/>
</div>
<div className="form-group">
<label htmlFor="password">Password *</label>
<input
type="password"
id="password"
name="password"
value={formData.password}
onChange={handlePasswordChange}
autoComplete="new-password"
minLength={8}
required
/>
<small className="form-hint">Minimum 8 characters.</small>
</div>
<div className="form-group">
<label htmlFor="confirmPassword">Confirm Password *</label>
<input
type="password"
id="confirmPassword"
name="confirmPassword"
value={confirmPassword}
onChange={handlePasswordChange}
autoComplete="new-password"
minLength={8}
className={confirmPassword ? (passwordsMatch ? 'field-success' : 'field-error') : ''}
required
/>
{confirmPassword ? (
<small className={passwordsMatch ? 'form-hint hint-success' : 'form-hint hint-error'}>
{passwordsMatch ? 'Passwords match.' : 'Passwords do not match.'}
</small>
) : (
<small className="form-hint">Re-enter your password to confirm it.</small>
)}
</div>
<div className="form-group form-group-full">
<label htmlFor="address">Address</label>
<textarea
id="address"
name="address"
value={formData.address}
onChange={handleChange}
rows={4}
autoComplete="street-address"
/>
</div>
<div className="form-group-full">
<button
type="submit"
className="btn btn-primary auth-submit"
disabled={loading}
>
{loading ? 'Creating Account...' : 'Create Account & Sign In'}
</button>
</div>
</form>
</div>
<div className="auth-footer">
<div>
Already have an account? <Link to="/login">Log in</Link>
</div>
</div>
</section>
</main>
</div>
);
};