refactor: update styles in MembersDirectory and NewsletterArchive for consistency and improved theming

- Updated color classes to use CSS variables for better maintainability and theming.
- Refactored component styles in MembersDirectory.js to enhance visual consistency.
- Adjusted loading states and empty states in NewsletterArchive.js for improved user experience.
- Added new brand colors to tailwind.config.js for future use.
This commit is contained in:
2026-01-12 20:10:33 -06:00
parent a93e2aa863
commit 7694532d53
77 changed files with 2519 additions and 2338 deletions

View File

@@ -163,9 +163,9 @@ const AcceptInvitation = () => {
const getRoleBadge = (role) => {
const config = {
superadmin: { label: 'Superadmin', className: 'bg-[#664fa3] text-white' },
admin: { label: 'Admin', className: 'bg-[#81B29A] text-white' },
member: { label: 'Member', className: 'bg-[#DDD8EB] text-[#422268]' }
superadmin: { label: 'Superadmin', className: 'bg-var(--purple-lavender) text-white' },
admin: { label: 'Admin', className: 'bg-var(--green-light) text-white' },
member: { label: 'Member', className: 'bg-var(--neutral-800) text-var(--purple-ink)' }
};
const roleConfig = config[role] || { label: role, className: 'bg-gray-500 text-white' };
@@ -179,10 +179,10 @@ const AcceptInvitation = () => {
if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-[#F9F8FB] to-white flex items-center justify-center p-4">
<Card className="w-full max-w-md p-12 bg-white rounded-2xl border border-[#ddd8eb] text-center">
<Loader2 className="h-12 w-12 text-[#664fa3] mx-auto mb-4 animate-spin" />
<p className="text-lg text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
<div className="min-h-screen bg-gradient-to-br from-var(--lavender-700) to-white flex items-center justify-center p-4">
<Card className="w-full max-w-md p-12 bg-background rounded-2xl border border-var(--neutral-800) text-center">
<Loader2 className="h-12 w-12 text-var(--purple-lavender) mx-auto mb-4 animate-spin" />
<p className="text-lg text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
Verifying your invitation...
</p>
</Card>
@@ -192,18 +192,18 @@ const AcceptInvitation = () => {
if (error) {
return (
<div className="min-h-screen bg-gradient-to-br from-[#F9F8FB] to-white flex items-center justify-center p-4">
<Card className="w-full max-w-md p-12 bg-white rounded-2xl border border-[#ddd8eb] text-center">
<div className="min-h-screen bg-gradient-to-br from-var(--lavender-700) to-white flex items-center justify-center p-4">
<Card className="w-full max-w-md p-12 bg-background rounded-2xl border border-var(--neutral-800) text-center">
<XCircle className="h-16 w-16 text-red-500 mx-auto mb-6" />
<h1 className="text-2xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
<h1 className="text-2xl font-semibold text-var(--purple-ink) mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
Invalid Invitation
</h1>
<p className="text-[#664fa3] mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-var(--purple-lavender) mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{error}
</p>
<Button
onClick={() => navigate('/login')}
className="rounded-xl bg-[#664fa3] hover:bg-[#422268] text-white"
className="rounded-xl bg-var(--purple-lavender) hover:bg-var(--purple-ink) text-white"
>
Go to Login
</Button>
@@ -216,53 +216,53 @@ const AcceptInvitation = () => {
const redirectPath = successUser?.role === 'admin' || successUser?.role === 'superadmin' ? '/admin' : '/dashboard';
return (
<div className="min-h-screen bg-gradient-to-br from-[#F9F8FB] to-white flex items-center justify-center p-4">
<Card className="w-full max-w-2xl p-12 bg-white rounded-2xl border border-[#ddd8eb] text-center">
<div className="min-h-screen bg-gradient-to-br from-var(--lavender-700) to-white flex items-center justify-center p-4">
<Card className="w-full max-w-2xl p-12 bg-background rounded-2xl border border-var(--neutral-800) text-center">
{/* Success Animation */}
<div className="mb-8">
<div className="h-24 w-24 mx-auto rounded-full bg-gradient-to-br from-[#81B29A] to-[#6DA085] flex items-center justify-center animate-bounce">
<div className="h-24 w-24 mx-auto rounded-full bg-gradient-to-br from-var(--green-light) to-var(--green-fern) flex items-center justify-center animate-bounce">
<CheckCircle className="h-12 w-12 text-white" />
</div>
</div>
{/* Success Message */}
<h1 className="text-4xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
<h1 className="text-4xl font-semibold text-var(--purple-ink) mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
Welcome to LOAF! 🎉
</h1>
<p className="text-xl text-[#664fa3] mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-xl text-var(--purple-lavender) mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Your account has been created successfully.
</p>
{/* User Info Card */}
<div className="mb-8 p-6 bg-gradient-to-r from-[#DDD8EB] to-[#F9F8FB] rounded-xl">
<div className="mb-8 p-6 bg-gradient-to-r from-var(--neutral-800) to-var(--lavender-700) rounded-xl">
<div className="grid md:grid-cols-2 gap-4 text-left">
<div>
<p className="text-sm text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Name
</p>
<p className="font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
{successUser?.first_name} {successUser?.last_name}
</p>
</div>
<div>
<p className="text-sm text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Email
</p>
<p className="font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
{successUser?.email}
</p>
</div>
<div>
<p className="text-sm text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Role
</p>
<div>{getRoleBadge(successUser?.role)}</div>
</div>
<div>
<p className="text-sm text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Status
</p>
<Badge className="bg-[#81B29A] text-white px-4 py-2 rounded-full text-sm">
<Badge className="bg-var(--green-light) text-white px-4 py-2 rounded-full text-sm">
{successUser?.status}
</Badge>
</div>
@@ -280,7 +280,7 @@ const AcceptInvitation = () => {
{/* Manual Continue Button */}
<Button
onClick={() => navigate(redirectPath)}
className="w-full h-14 rounded-xl bg-gradient-to-r from-[#81B29A] to-[#6DA085] hover:from-[#6DA085] hover:to-[#5A8F72] text-white text-lg font-semibold"
className="w-full h-14 rounded-xl bg-gradient-to-r from-var(--green-light) to-var(--green-fern) hover:from-var(--green-fern) hover:to-var(--green-sage] text-white text-lg font-semibold"
>
Continue to Dashboard
</Button>
@@ -290,46 +290,46 @@ const AcceptInvitation = () => {
}
return (
<div className="min-h-screen bg-gradient-to-br from-[#F9F8FB] to-white flex items-center justify-center p-4">
<Card className="w-full max-w-3xl p-8 md:p-12 bg-white rounded-2xl border border-[#ddd8eb]">
<div className="min-h-screen bg-gradient-to-br from-var(--lavender-700) to-white flex items-center justify-center p-4">
<Card className="w-full max-w-3xl p-8 md:p-12 bg-background rounded-2xl border border-var(--neutral-800)">
{/* Header */}
<div className="text-center mb-8">
<div className="flex justify-center mb-4">
<div className="h-16 w-16 rounded-full bg-gradient-to-br from-[#664fa3] to-[#422268] flex items-center justify-center">
<div className="h-16 w-16 rounded-full bg-gradient-to-br from-var(--purple-lavender) to-var(--purple-ink) flex items-center justify-center">
<Mail className="h-8 w-8 text-white" />
</div>
</div>
<h1 className="text-3xl md:text-4xl font-semibold text-[#422268] mb-3" style={{ fontFamily: "'Inter', sans-serif" }}>
<h1 className="text-3xl md:text-4xl font-semibold text-var(--purple-ink) mb-3" style={{ fontFamily: "'Inter', sans-serif" }}>
Welcome to LOAF!
</h1>
<p className="text-lg text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-lg text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Complete your profile to accept the invitation
</p>
</div>
{/* Invitation Details */}
<div className="mb-8 p-6 bg-gradient-to-r from-[#DDD8EB] to-[#F9F8FB] rounded-xl">
<div className="mb-8 p-6 bg-gradient-to-r from-var(--neutral-800) to-var(--lavender-700) rounded-xl">
<div className="grid md:grid-cols-2 gap-4 text-sm">
<div>
<p className="text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Email Address
</p>
<p className="font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
{invitation?.email}
</p>
</div>
<div>
<p className="text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Role
</p>
<div>{getRoleBadge(invitation?.role)}</div>
</div>
<div className="md:col-span-2">
<p className="text-[#664fa3] mb-1 flex items-center gap-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-var(--purple-lavender) mb-1 flex items-center gap-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<Calendar className="h-4 w-4" />
Invitation Expires
</p>
<p className="font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
{invitation?.expires_at ? new Date(invitation.expires_at).toLocaleString() : 'N/A'}
</p>
</div>
@@ -342,7 +342,7 @@ const AcceptInvitation = () => {
{/* Password Fields */}
<div className="grid md:grid-cols-2 gap-4">
<div className="grid gap-2">
<Label htmlFor="password" className="text-[#422268]">
<Label htmlFor="password" className="text-var(--purple-ink)">
Password <span className="text-red-500">*</span>
</Label>
<Input
@@ -350,7 +350,7 @@ const AcceptInvitation = () => {
type="password"
value={formData.password}
onChange={(e) => handleChange('password', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="Minimum 8 characters"
/>
{formErrors.password && (
@@ -359,7 +359,7 @@ const AcceptInvitation = () => {
</div>
<div className="grid gap-2">
<Label htmlFor="confirmPassword" className="text-[#422268]">
<Label htmlFor="confirmPassword" className="text-var(--purple-ink)">
Confirm Password <span className="text-red-500">*</span>
</Label>
<Input
@@ -367,7 +367,7 @@ const AcceptInvitation = () => {
type="password"
value={formData.confirmPassword}
onChange={(e) => handleChange('confirmPassword', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="Re-enter password"
/>
{formErrors.confirmPassword && (
@@ -379,14 +379,14 @@ const AcceptInvitation = () => {
{/* Name Fields */}
<div className="grid md:grid-cols-2 gap-4">
<div className="grid gap-2">
<Label htmlFor="first_name" className="text-[#422268]">
<Label htmlFor="first_name" className="text-var(--purple-ink)">
First Name <span className="text-red-500">*</span>
</Label>
<Input
id="first_name"
value={formData.first_name}
onChange={(e) => handleChange('first_name', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="John"
/>
{formErrors.first_name && (
@@ -395,14 +395,14 @@ const AcceptInvitation = () => {
</div>
<div className="grid gap-2">
<Label htmlFor="last_name" className="text-[#422268]">
<Label htmlFor="last_name" className="text-var(--purple-ink)">
Last Name <span className="text-red-500">*</span>
</Label>
<Input
id="last_name"
value={formData.last_name}
onChange={(e) => handleChange('last_name', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="Doe"
/>
{formErrors.last_name && (
@@ -413,7 +413,7 @@ const AcceptInvitation = () => {
{/* Phone */}
<div className="grid gap-2">
<Label htmlFor="phone" className="text-[#422268]">
<Label htmlFor="phone" className="text-var(--purple-ink)">
Phone <span className="text-red-500">*</span>
</Label>
<Input
@@ -421,7 +421,7 @@ const AcceptInvitation = () => {
type="tel"
value={formData.phone}
onChange={(e) => handleChange('phone', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="(555) 123-4567"
/>
{formErrors.phone && (
@@ -432,20 +432,20 @@ const AcceptInvitation = () => {
{/* Optional Fields Section */}
{invitation?.role === 'member' && (
<>
<div className="border-t border-[#ddd8eb] pt-6 mt-2">
<h3 className="text-lg font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
<div className="border-t border-var(--neutral-800) pt-6 mt-2">
<h3 className="text-lg font-semibold text-var(--purple-ink) mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
Additional Information (Optional)
</h3>
</div>
{/* Address */}
<div className="grid gap-2">
<Label htmlFor="address" className="text-[#422268]">Address</Label>
<Label htmlFor="address" className="text-var(--purple-ink)">Address</Label>
<Input
id="address"
value={formData.address}
onChange={(e) => handleChange('address', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="123 Main St"
/>
</div>
@@ -453,35 +453,35 @@ const AcceptInvitation = () => {
{/* City, State, Zipcode */}
<div className="grid md:grid-cols-3 gap-4">
<div className="grid gap-2">
<Label htmlFor="city" className="text-[#422268]">City</Label>
<Label htmlFor="city" className="text-var(--purple-ink)">City</Label>
<Input
id="city"
value={formData.city}
onChange={(e) => handleChange('city', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="San Francisco"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="state" className="text-[#422268]">State</Label>
<Label htmlFor="state" className="text-var(--purple-ink)">State</Label>
<Input
id="state"
value={formData.state}
onChange={(e) => handleChange('state', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="CA"
maxLength={2}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="zipcode" className="text-[#422268]">Zipcode</Label>
<Label htmlFor="zipcode" className="text-var(--purple-ink)">Zipcode</Label>
<Input
id="zipcode"
value={formData.zipcode}
onChange={(e) => handleChange('zipcode', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
placeholder="94102"
/>
</div>
@@ -489,13 +489,13 @@ const AcceptInvitation = () => {
{/* Date of Birth */}
<div className="grid gap-2">
<Label htmlFor="date_of_birth" className="text-[#422268]">Date of Birth</Label>
<Label htmlFor="date_of_birth" className="text-var(--purple-ink)">Date of Birth</Label>
<Input
id="date_of_birth"
type="date"
value={formData.date_of_birth}
onChange={(e) => handleChange('date_of_birth', e.target.value)}
className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
/>
</div>
</>
@@ -507,7 +507,7 @@ const AcceptInvitation = () => {
<Button
type="submit"
disabled={submitting}
className="w-full h-14 rounded-xl bg-gradient-to-r from-[#81B29A] to-[#6DA085] hover:from-[#6DA085] hover:to-[#5A8F72] text-white text-lg font-semibold"
className="w-full h-14 rounded-xl bg-gradient-to-r from-var(--green-light) to-var(--green-fern) hover:from-var(--green-fern) hover:to-var(--green-sage] text-white text-lg font-semibold"
>
{submitting ? (
<>
@@ -526,11 +526,11 @@ const AcceptInvitation = () => {
{/* Footer Note */}
<div className="mt-6 text-center">
<p className="text-sm text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Already have an account?{' '}
<button
onClick={() => navigate('/login')}
className="text-[#664fa3] hover:text-[#422268] font-semibold underline"
className="text-var(--purple-lavender) hover:text-var(--purple-ink) font-semibold underline"
>
Sign in instead
</button>