Refactor color scheme in member-related pages to use brand colors instead of CSS variables for consistency and improved readability

This commit is contained in:
2026-01-13 22:01:33 -06:00
parent 30d32d8823
commit e04d39fe17
61 changed files with 731 additions and 735 deletions

View File

@@ -187,7 +187,7 @@ export default function AddToCalendarButton({
>
<RefreshCw className="h-4 w-4 mr-2" />
Subscribe to My Events
<div className="text-xs text-[var(--purple-lavender)] mt-0.5">
<div className="text-xs text-brand-purple mt-0.5">
Auto-syncs your RSVP'd events
</div>
</DropdownMenuItem>
@@ -198,7 +198,7 @@ export default function AddToCalendarButton({
>
<Download className="h-4 w-4 mr-2" />
Download All Events
<div className="text-xs text-[var(--purple-lavender)] mt-0.5">
<div className="text-xs text-brand-purple mt-0.5">
One-time import of all upcoming events
</div>
</DropdownMenuItem>
@@ -206,7 +206,7 @@ export default function AddToCalendarButton({
)}
{!event && !showSubscribe && (
<div className="px-2 py-6 text-center text-sm text-[var(--purple-lavender)]">
<div className="px-2 py-6 text-center text-sm text-brand-purple ">
No event selected
</div>
)}

View File

@@ -211,7 +211,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
className={`
flex items-center gap-3 px-4 py-3 rounded-lg transition-all relative
${item.disabled
? 'opacity-50 cursor-not-allowed text-[var(--purple-lavender)]'
? 'opacity-50 cursor-not-allowed text-brand-purple '
: active
? 'bg-[var(--orange-light)]/10 text-[var(--orange-light)]'
: 'text-[var(--purple-ink)] hover:bg-[var(--neutral-800)]/20'

View File

@@ -64,12 +64,12 @@ export const AttendanceDialog = ({ event, open, onOpenChange, onSuccess }) => {
<div className="space-y-4 mt-4">
{rsvps.length === 0 ? (
<p className="text-center text-[var(--purple-lavender)] py-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>No RSVPs yet</p>
<p className="text-center text-brand-purple py-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>No RSVPs yet</p>
) : (
rsvps.map((rsvp) => (
<div
key={rsvp.user_id}
className="flex items-center gap-3 p-4 border-2 border-[var(--neutral-800)] rounded-xl hover:border-[var(--purple-lavender)] transition-colors"
className="flex items-center gap-3 p-4 border-2 border-[var(--neutral-800)] rounded-xl hover:border-brand-purple transition-colors"
>
<Checkbox
checked={attendance[rsvp.user_id] || false}
@@ -80,7 +80,7 @@ export const AttendanceDialog = ({ event, open, onOpenChange, onSuccess }) => {
/>
<div className="flex-1">
<p className="font-medium text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>{rsvp.user_name}</p>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>{rsvp.user_email}</p>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>{rsvp.user_email}</p>
</div>
{rsvp.attended && (
<span className="text-sm text-[var(--green-light)] font-medium">
@@ -103,7 +103,7 @@ export const AttendanceDialog = ({ event, open, onOpenChange, onSuccess }) => {
<Button
onClick={() => onOpenChange(false)}
variant="outline"
className="flex-1 border-2 border-[var(--neutral-800)] text-[var(--purple-lavender)] hover:bg-background hover:text-[var(--purple-ink)] rounded-full"
className="flex-1 border-2 border-[var(--neutral-800)] text-brand-purple hover:bg-background hover:text-[var(--purple-ink)] rounded-full"
>
Cancel
</Button>

View File

@@ -76,7 +76,7 @@ const ChangePasswordDialog = ({ open, onOpenChange }) => {
Change Password
</DialogTitle>
</div>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Update your password to keep your account secure.
</DialogDescription>
</DialogHeader>
@@ -92,7 +92,7 @@ const ChangePasswordDialog = ({ open, onOpenChange }) => {
value={formData.currentPassword}
onChange={handleInputChange}
placeholder="Enter current password"
className="h-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -106,7 +106,7 @@ const ChangePasswordDialog = ({ open, onOpenChange }) => {
value={formData.newPassword}
onChange={handleInputChange}
placeholder="Enter new password (min. 6 characters)"
className="h-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -120,7 +120,7 @@ const ChangePasswordDialog = ({ open, onOpenChange }) => {
value={formData.confirmPassword}
onChange={handleInputChange}
placeholder="Re-enter new password"
className="h-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>

View File

@@ -48,8 +48,8 @@ const ConfirmationDialog = ({
},
info: {
icon: Info,
iconColor: 'text-[var(--purple-lavender)]',
confirmButtonClass: 'bg-[var(--purple-lavender)] text-white hover:bg-[var(--purple-plum)] rounded-full px-6',
iconColor: 'text-brand-purple ',
confirmButtonClass: 'bg-brand-purple text-white hover:bg-[var(--purple-plum)] rounded-full px-6',
},
success: {
icon: CheckCircle,
@@ -77,7 +77,7 @@ const ConfirmationDialog = ({
{title}
</AlertDialogTitle>
<AlertDialogDescription
className="text-[var(--purple-lavender)] text-sm leading-relaxed"
className="text-brand-purple text-sm leading-relaxed"
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
>
{description}
@@ -87,7 +87,7 @@ const ConfirmationDialog = ({
</AlertDialogHeader>
<AlertDialogFooter className="p-6 pt-4 bg-[var(--lavender-500)] flex-row gap-3 justify-end">
<AlertDialogCancel
className="border-2 border-[var(--neutral-800)] text-[var(--purple-lavender)] hover:bg-background rounded-full px-6"
className="border-2 border-[var(--neutral-800)] text-brand-purple hover:bg-background rounded-full px-6"
disabled={loading}
>
{cancelText}

View File

@@ -125,7 +125,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
<UserPlus className="h-6 w-6" />
Create Member
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Create a new member account with direct login access. Member will be created immediately.
</DialogDescription>
</DialogHeader>
@@ -143,7 +143,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
type="email"
value={formData.email}
onChange={(e) => handleChange('email', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="member@example.com"
/>
{errors.email && (
@@ -160,7 +160,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
type="password"
value={formData.password}
onChange={(e) => handleChange('password', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="Minimum 8 characters"
/>
{errors.password && (
@@ -179,7 +179,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
id="first_name"
value={formData.first_name}
onChange={(e) => handleChange('first_name', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="John"
/>
{errors.first_name && (
@@ -195,7 +195,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
id="last_name"
value={formData.last_name}
onChange={(e) => handleChange('last_name', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="Doe"
/>
{errors.last_name && (
@@ -214,7 +214,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
type="tel"
value={formData.phone}
onChange={(e) => handleChange('phone', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="(555) 123-4567"
/>
{errors.phone && (
@@ -231,7 +231,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
id="address"
value={formData.address}
onChange={(e) => handleChange('address', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="123 Main St"
/>
</div>
@@ -244,7 +244,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
id="city"
value={formData.city}
onChange={(e) => handleChange('city', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="San Francisco"
/>
</div>
@@ -255,7 +255,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
id="state"
value={formData.state}
onChange={(e) => handleChange('state', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="CA"
maxLength={2}
/>
@@ -267,7 +267,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
id="zipcode"
value={formData.zipcode}
onChange={(e) => handleChange('zipcode', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="94102"
/>
</div>
@@ -282,7 +282,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
type="date"
value={formData.date_of_birth}
onChange={(e) => handleChange('date_of_birth', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -293,7 +293,7 @@ const CreateMemberDialog = ({ open, onOpenChange, onSuccess }) => {
type="date"
value={formData.member_since}
onChange={(e) => handleChange('member_since', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
</div>

View File

@@ -105,7 +105,7 @@ const CreateStaffDialog = ({ open, onOpenChange, onSuccess }) => {
<UserPlus className="h-6 w-6" />
Create Staff Member
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Create a new staff account with direct login access. User will be created immediately.
</DialogDescription>
</DialogHeader>
@@ -122,7 +122,7 @@ const CreateStaffDialog = ({ open, onOpenChange, onSuccess }) => {
type="email"
value={formData.email}
onChange={(e) => handleChange('email', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="staff@example.com"
/>
{errors.email && (
@@ -140,7 +140,7 @@ const CreateStaffDialog = ({ open, onOpenChange, onSuccess }) => {
type="password"
value={formData.password}
onChange={(e) => handleChange('password', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="Minimum 8 characters"
/>
{errors.password && (
@@ -157,7 +157,7 @@ const CreateStaffDialog = ({ open, onOpenChange, onSuccess }) => {
id="first_name"
value={formData.first_name}
onChange={(e) => handleChange('first_name', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="John"
/>
{errors.first_name && (
@@ -174,7 +174,7 @@ const CreateStaffDialog = ({ open, onOpenChange, onSuccess }) => {
id="last_name"
value={formData.last_name}
onChange={(e) => handleChange('last_name', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="Doe"
/>
{errors.last_name && (
@@ -192,7 +192,7 @@ const CreateStaffDialog = ({ open, onOpenChange, onSuccess }) => {
type="tel"
value={formData.phone}
onChange={(e) => handleChange('phone', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="(555) 123-4567"
/>
{errors.phone && (

View File

@@ -144,7 +144,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
<Upload className="h-6 w-6" />
{importResult ? 'Import Results' : 'Import Members from CSV'}
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{importResult
? 'Review the import results below'
: 'Upload a CSV file to bulk import members. Ensure the CSV has the required columns.'}
@@ -155,7 +155,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
// Upload Form
<div className="grid gap-6 py-4">
{/* CSV Format Instructions */}
<Alert className="border-[var(--purple-lavender)] bg-[var(--lavender-700)]">
<Alert className="border-brand-purple bg-[var(--lavender-700)]">
<AlertDescription className="text-sm text-[var(--purple-ink)]">
<strong>Required columns:</strong> Email, First Name, Last Name, Phone, Role
<br />
@@ -168,8 +168,8 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
{/* File Upload Area */}
<div
className={`border-2 border-dashed rounded-2xl p-12 text-center transition-colors ${dragActive
? 'border-[var(--purple-lavender)] bg-[var(--lavender-700)]'
: 'border-[var(--neutral-800)] hover:border-[var(--purple-lavender)] hover:bg-[var(--lavender-700)]'
? 'border-brand-purple bg-[var(--lavender-700)]'
: 'border-[var(--neutral-800)] hover:border-brand-purple hover:bg-[var(--lavender-700)]'
}`}
onDragEnter={handleDrag}
onDragLeave={handleDrag}
@@ -183,7 +183,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
<p className="text-lg font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
{file.name}
</p>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
{(file.size / 1024).toFixed(2)} KB
</p>
</div>
@@ -203,7 +203,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
<p className="text-lg font-semibold text-[var(--purple-ink)] mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
Drag and drop your CSV file here
</p>
<p className="text-sm text-[var(--purple-lavender)] mb-4">or</p>
<p className="text-sm text-brand-purple mb-4">or</p>
<Label htmlFor="file-upload">
<Button variant="outline" className="rounded-xl cursor-pointer" asChild>
<span>Browse Files</span>
@@ -227,7 +227,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
checked={updateExisting}
onCheckedChange={setUpdateExisting}
id="update-existing"
className="h-5 w-5 border-2 border-[var(--purple-lavender)] data-[state=checked]:bg-[var(--purple-lavender)]"
className="h-5 w-5 border-2 border-brand-purple data-[state=checked]:bg-brand-purple "
/>
<Label htmlFor="update-existing" className="text-[var(--purple-ink)] cursor-pointer">
Update existing members (if email already exists)
@@ -240,7 +240,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
{/* Summary Cards */}
<div className="grid md:grid-cols-4 gap-4">
<div className="p-4 bg-background rounded-xl border border-[var(--neutral-800)] text-center">
<p className="text-sm text-[var(--purple-lavender)] mb-1">Total Rows</p>
<p className="text-sm text-brand-purple mb-1">Total Rows</p>
<p className="text-2xl font-semibold text-[var(--purple-ink)]">{importResult.total_rows}</p>
</div>
<div className="p-4 bg-green-50 rounded-xl border border-green-200 text-center">
@@ -276,7 +276,7 @@ const ImportMembersDialog = ({ open, onOpenChange, onSuccess }) => {
{importResult.errors.map((error, idx) => (
<TableRow key={idx} className="hover:bg-[var(--lavender-700)]">
<TableCell className="font-medium text-[var(--purple-ink)]">{error.row}</TableCell>
<TableCell className="text-[var(--purple-lavender)]">{error.email}</TableCell>
<TableCell className="text-brand-purple ">{error.email}</TableCell>
<TableCell className="text-red-600 text-sm">{error.error}</TableCell>
</TableRow>
))}

View File

@@ -129,7 +129,7 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
<Mail className="h-6 w-6" />
{invitationUrl ? 'Invitation Sent' : 'Invite Staff Member'}
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{invitationUrl
? 'The invitation has been sent via email. You can also copy the link below.'
: 'Send an email invitation to join as staff. They will set their own password.'}
@@ -148,7 +148,7 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
/>
<Button
onClick={copyToClipboard}
className="rounded-xl bg-[var(--purple-lavender)] hover:bg-[var(--purple-ink)] text-white flex-shrink-0"
className="rounded-xl bg-brand-purple hover:bg-[var(--purple-ink)] text-white flex-shrink-0"
>
{copied ? (
<>
@@ -178,7 +178,7 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
type="email"
value={formData.email}
onChange={(e) => handleChange('email', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="staff@example.com"
/>
{errors.email && (
@@ -195,7 +195,7 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
id="first_name"
value={formData.first_name}
onChange={(e) => handleChange('first_name', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="John"
/>
</div>
@@ -209,7 +209,7 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
id="last_name"
value={formData.last_name}
onChange={(e) => handleChange('last_name', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="Doe"
/>
</div>
@@ -224,7 +224,7 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
type="tel"
value={formData.phone}
onChange={(e) => handleChange('phone', e.target.value)}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
placeholder="(555) 123-4567"
/>
</div>

View File

@@ -4,7 +4,7 @@ import { Calendar, Users, User, BookOpen, FileText, DollarSign, Scale } from 'lu
const MemberFooter = () => {
return (
<footer className="bg-[var(--purple-ink)] text-white mt-auto">
<footer className="bg-brand-dark-lavender text-white mt-auto">
<div className="max-w-7xl mx-auto px-6 py-12">
<div className="grid md:grid-cols-4 gap-8">
{/* Logo & About */}
@@ -89,12 +89,12 @@ const MemberFooter = () => {
</Link>
</li>
<li>
<a href="/#contact" className="text-gray-300 hover:text-white transition-colors">
<a href="/membership/contact-us" className="text-gray-300 hover:text-white transition-colors">
Contact Us
</a>
</li>
<li>
<a href="/#donate" className="text-gray-300 hover:text-white transition-colors">
<a href="/membership/donate" className="text-gray-300 hover:text-white transition-colors">
Donate
</a>
</li>
@@ -106,10 +106,10 @@ const MemberFooter = () => {
{/* Bottom Bar */}
<div className="border-t border-[var(--purple-lavender)]">
<div className="max-w-7xl mx-auto px-6 py-4">
<div className="flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-gray-400" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<div className="flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-gray-300" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<div className="flex gap-6">
<a href="/#terms" className="hover:text-white transition-colors">Terms of Service</a>
<a href="/#privacy" className="hover:text-white transition-colors">Privacy Policy</a>
<a href="/membership/terms-of-service" className="hover:text-white transition-colors">Terms of Service</a>
<a href="/membership/privacy-policy" className="hover:text-white transition-colors">Privacy Policy</a>
</div>
<p>© 2025 LOAF. All rights reserved.</p>
</div>

View File

@@ -162,7 +162,7 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
<DialogTitle className="text-2xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Activate Manual Payment
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Record offline payment for {user.first_name} {user.last_name} ({user.email})
</DialogDescription>
</DialogHeader>
@@ -203,7 +203,7 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
</SelectContent>
</Select>
{selectedPlan && (
<p className="text-xs text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-xs text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{selectedPlan.description || `${selectedPlan.billing_cycle} subscription`}
</p>
)}
@@ -222,11 +222,11 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
placeholder="Enter amount"
value={formData.amount}
onChange={(e) => setFormData({ ...formData, amount: e.target.value })}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
required
/>
{selectedPlan && (
<p className="text-xs text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-xs text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Minimum: {formatPrice(selectedPlan.minimum_price_cents || selectedPlan.price_cents || 3000)}
</p>
)}
@@ -263,13 +263,13 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
Payment Date
</Label>
<div className="relative">
<Calendar className="absolute left-4 top-1/2 transform -translate-y-1/2 h-5 w-5 text-[var(--purple-lavender)]" />
<Calendar className="absolute left-4 top-1/2 transform -translate-y-1/2 h-5 w-5 text-brand-purple " />
<Input
id="payment_date"
type="date"
value={formData.payment_date}
onChange={(e) => setFormData({ ...formData, payment_date: e.target.value })}
className="pl-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="pl-12 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
required
/>
</div>
@@ -308,7 +308,7 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
onChange={(e) => setUseCustomPeriod(e.target.checked)}
className="rounded border-[var(--neutral-800)]"
/>
<Label htmlFor="use_custom_period" className="text-sm text-[var(--purple-lavender)] font-normal cursor-pointer" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<Label htmlFor="use_custom_period" className="text-sm text-brand-purple font-normal cursor-pointer" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Use custom dates instead of plan's billing cycle
</Label>
</div>
@@ -324,7 +324,7 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
type="date"
value={formData.custom_period_start}
onChange={(e) => setFormData({ ...formData, custom_period_start: e.target.value })}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
required={useCustomPeriod}
/>
</div>
@@ -337,14 +337,14 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
type="date"
value={formData.custom_period_end}
onChange={(e) => setFormData({ ...formData, custom_period_end: e.target.value })}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
required={useCustomPeriod}
/>
</div>
</div>
) : (
selectedPlan && (
<div className="text-sm text-[var(--purple-lavender)] bg-[var(--lavender-300)] p-3 rounded-lg space-y-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<div className="text-sm text-brand-purple bg-[var(--lavender-300)] p-3 rounded-lg space-y-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{selectedPlan.custom_cycle_enabled ? (
<>
<p>
@@ -386,7 +386,7 @@ const PaymentActivationDialog = ({ open, onOpenChange, user, onSuccess }) => {
placeholder="Additional notes about the payment..."
value={formData.notes}
onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)] min-h-[100px]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple min-h-[100px]"
/>
</div>

View File

@@ -73,7 +73,7 @@ const PendingInvitationsTable = () => {
const getRoleBadge = (role) => {
const config = {
superadmin: { label: 'Superadmin', className: 'bg-[var(--purple-lavender)] text-white' },
superadmin: { label: 'Superadmin', className: 'bg-brand-purple text-white' },
admin: { label: 'Admin', className: 'bg-[var(--green-light)] text-white' },
member: { label: 'Member', className: 'bg-[var(--neutral-800)] text-[var(--purple-ink)]' }
};
@@ -111,7 +111,7 @@ const PendingInvitationsTable = () => {
if (loading) {
return (
<div className="text-center py-8">
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Loading invitations...
</p>
</div>
@@ -125,7 +125,7 @@ const PendingInvitationsTable = () => {
<h3 className="text-xl font-semibold text-[var(--purple-ink)] mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
No Pending Invitations
</h3>
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
All invitations have been accepted or expired
</p>
</Card>
@@ -152,19 +152,19 @@ const PendingInvitationsTable = () => {
<TableCell className="font-medium text-[var(--purple-ink)]">
{invitation.email}
</TableCell>
<TableCell className="text-[var(--purple-lavender)]">
<TableCell className="text-brand-purple ">
{invitation.first_name && invitation.last_name
? `${invitation.first_name} ${invitation.last_name}`
: '-'}
</TableCell>
<TableCell>{getRoleBadge(invitation.role)}</TableCell>
<TableCell className="text-[var(--purple-lavender)]">
<TableCell className="text-brand-purple ">
{new Date(invitation.invited_at).toLocaleDateString()}
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Clock className={`h-4 w-4 ${isExpiringSoon(invitation.expires_at) ? 'text-orange-500' : 'text-[var(--purple-lavender)]'}`} />
<span className={`text-sm ${isExpiringSoon(invitation.expires_at) ? 'text-orange-500 font-semibold' : 'text-[var(--purple-lavender)]'}`}>
<Clock className={`h-4 w-4 ${isExpiringSoon(invitation.expires_at) ? 'text-orange-500' : 'text-brand-purple '}`} />
<span className={`text-sm ${isExpiringSoon(invitation.expires_at) ? 'text-orange-500 font-semibold' : 'text-brand-purple '}`}>
{formatDate(invitation.expires_at)}
</span>
</div>
@@ -211,7 +211,7 @@ const PendingInvitationsTable = () => {
<AlertDialogTitle className="text-2xl text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Revoke Invitation
</AlertDialogTitle>
<AlertDialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<AlertDialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Are you sure you want to revoke the invitation for{' '}
<span className="font-semibold">{revokeDialog.invitation?.email}</span>?
This action cannot be undone.

View File

@@ -164,7 +164,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
<DialogTitle className="text-2xl text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
{plan ? 'Edit Plan' : 'Create New Plan'}
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{plan ? 'Update plan details below' : 'Enter plan details to create a new subscription plan'}
</DialogDescription>
</DialogHeader>
@@ -216,7 +216,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
required
className="mt-2"
/>
<p className="text-xs text-[var(--purple-lavender)] mt-1">Minimum $30</p>
<p className="text-xs text-brand-purple mt-1">Minimum $30</p>
</div>
<div>
@@ -232,7 +232,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
required
className="mt-2"
/>
<p className="text-xs text-[var(--purple-lavender)] mt-1">Pre-filled amount</p>
<p className="text-xs text-brand-purple mt-1">Pre-filled amount</p>
</div>
</div>
@@ -240,7 +240,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
<div className="flex items-center justify-between pt-2">
<div>
<Label htmlFor="allow_donation">Allow Donations</Label>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Members can pay more than minimum
</p>
</div>
@@ -252,7 +252,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
onChange={(e) => setFormData({ ...formData, allow_donation: e.target.checked })}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--purple-lavender)]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--green-light)]"></div>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-purple /20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--green-light)]"></div>
</label>
</div>
</div>
@@ -283,7 +283,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
<h3 className="font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Custom Billing Period
</h3>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Set recurring date range (e.g., Jan 1 - Dec 31 for calendar year)
</p>
@@ -361,7 +361,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
<div className="flex items-center justify-between">
<div>
<Label htmlFor="active">Active Status</Label>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Inactive plans won't appear for new subscriptions
</p>
</div>
@@ -373,7 +373,7 @@ const PlanDialog = ({ open, onOpenChange, plan, onSuccess }) => {
onChange={(e) => setFormData({ ...formData, active: e.target.checked })}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[var(--purple-lavender)]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--green-light)]"></div>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-purple /20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[var(--green-light)]"></div>
</label>
</div>

View File

@@ -105,7 +105,7 @@ const PublicNavbar = () => {
</header>
{/* Main Header - Navigation */}
<header className=" bg-[var(--purple-lavender)] px-[20px] py-2 flex justify-between items-center">
<header className=" bg-brand-purple px-[20px] py-2 flex justify-between items-center">
<Link to="/">
<img src={loafLogo} alt="LOAF Logo" className="h-16 w-16 sm:h-20 sm:w-20 md:h-28 md:w-28 object-contain" />
</Link>
@@ -204,7 +204,7 @@ const PublicNavbar = () => {
/>
{/* Drawer */}
<div className="fixed right-0 top-0 h-full w-[280px] bg-[var(--purple-lavender)] shadow-xl overflow-y-auto">
<div className="fixed right-0 top-0 h-full w-[280px] bg-brand-purple shadow-xl overflow-y-auto">
{/* Header */}
<div className="flex justify-between items-center p-6 border-b border-[var(--purple-deep)]">
<span className="text-white text-lg font-semibold" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>

View File

@@ -41,17 +41,17 @@ export default function RejectionDialog({ open, onOpenChange, onConfirm, user, l
Reject Application
</DialogTitle>
</div>
<DialogDescription className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<DialogDescription className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
You are about to reject <strong>{user?.first_name} {user?.last_name}</strong>'s membership application.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="bg-[var(--lavender-400)] border border-[var(--neutral-800)] rounded-lg p-4">
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<strong>Applicant:</strong> {user?.email}
</p>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<strong>Status:</strong> {user?.status}
</p>
</div>
@@ -74,7 +74,7 @@ export default function RejectionDialog({ open, onOpenChange, onConfirm, user, l
{error && (
<p className="text-sm text-red-500">{error}</p>
)}
<p className="text-xs text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-xs text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
The applicant will receive an email with this reason.
</p>
</div>
@@ -85,7 +85,7 @@ export default function RejectionDialog({ open, onOpenChange, onConfirm, user, l
type="button"
onClick={handleClose}
variant="outline"
className="border-2 border-[var(--neutral-800)] text-[var(--purple-lavender)] hover:bg-[var(--lavender-300)] rounded-full px-6"
className="border-2 border-[var(--neutral-800)] text-brand-purple hover:bg-[var(--lavender-300)] rounded-full px-6"
disabled={loading}
>
<X className="h-4 w-4 mr-2" />

View File

@@ -371,14 +371,14 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold text-[var(--purple-ink)] mb-2">Upload WordPress CSV Export</h3>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
Select the WordPress user export CSV file. The file will be analyzed for data quality issues.
</p>
</div>
<Card className="p-6 border-2 border-dashed border-[var(--neutral-800)] bg-[var(--lavender-400)]">
<div className="flex flex-col items-center gap-4">
<Upload className="h-12 w-12 text-[var(--purple-lavender)]" />
<Upload className="h-12 w-12 text-brand-purple " />
<div className="text-center">
<Input
type="file"
@@ -387,7 +387,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
className="max-w-xs"
/>
{uploadedFile && (
<p className="text-sm text-[var(--purple-lavender)] mt-2">
<p className="text-sm text-brand-purple mt-2">
Selected: {uploadedFile.name}
</p>
)}
@@ -399,7 +399,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<Button
onClick={handleUpload}
disabled={uploading}
className="w-full bg-[var(--purple-lavender)] hover:bg-[var(--purple-ink)]"
className="w-full bg-brand-purple hover:bg-[var(--purple-ink)]"
>
{uploading ? (
<>
@@ -466,7 +466,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold text-[var(--purple-ink)] mb-2">Field Mapping</h3>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
WordPress fields have been automatically mapped to LOAF platform fields.
</p>
</div>
@@ -538,7 +538,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold text-[var(--purple-ink)] mb-2">Review & Adjust User Status</h3>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
Review suggested status mappings and override as needed before import.
</p>
</div>
@@ -550,7 +550,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
checked={selectedRows.size === previewData.length && previewData.length > 0}
onCheckedChange={toggleSelectAll}
/>
<span className="text-sm text-[var(--purple-lavender)] font-medium">
<span className="text-sm text-brand-purple font-medium">
{selectedRows.size > 0 ? `${selectedRows.size} selected` : 'Select all'}
</span>
{selectedRows.size > 0 && (
@@ -572,7 +572,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
{/* Data table */}
{loading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-[var(--purple-lavender)]" />
<Loader2 className="h-8 w-8 animate-spin text-brand-purple " />
</div>
) : (
<div className="border rounded-lg overflow-hidden">
@@ -651,7 +651,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
{/* Pagination */}
{totalPages > 1 && (
<div className="flex items-center justify-between">
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
Page {currentPage} of {totalPages}
</p>
<div className="flex gap-2">
@@ -690,22 +690,22 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold text-[var(--purple-ink)] mb-2">Import Preview</h3>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
Review the final import settings before execution.
</p>
</div>
<div className="grid md:grid-cols-3 gap-4">
<Card className="p-6">
<p className="text-sm text-[var(--purple-lavender)]">Total Users</p>
<p className="text-sm text-brand-purple ">Total Users</p>
<p className="text-3xl font-semibold text-[var(--purple-ink)]">{analysisResult?.total_rows}</p>
</Card>
<Card className="p-6">
<p className="text-sm text-[var(--purple-lavender)]">Status Overrides</p>
<p className="text-sm text-brand-purple ">Status Overrides</p>
<p className="text-3xl font-semibold text-[var(--purple-ink)]">{overrideCount}</p>
</Card>
<Card className="p-6">
<p className="text-sm text-[var(--purple-lavender)]">Expected Imports</p>
<p className="text-sm text-brand-purple ">Expected Imports</p>
<p className="text-3xl font-semibold text-[var(--purple-ink)]">{analysisResult?.valid_rows}</p>
</Card>
</div>
@@ -715,15 +715,15 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div className="space-y-3">
<div className="flex items-center gap-2">
<CheckCircle className="h-5 w-5 text-green-600" />
<span className="text-sm text-[var(--purple-lavender)]">Send password reset emails to all imported users</span>
<span className="text-sm text-brand-purple ">Send password reset emails to all imported users</span>
</div>
<div className="flex items-center gap-2">
<CheckCircle className="h-5 w-5 text-green-600" />
<span className="text-sm text-[var(--purple-lavender)]">Skip rows with errors and continue import</span>
<span className="text-sm text-brand-purple ">Skip rows with errors and continue import</span>
</div>
<div className="flex items-center gap-2">
<CheckCircle className="h-5 w-5 text-green-600" />
<span className="text-sm text-[var(--purple-lavender)]">Full rollback capability available after import</span>
<span className="text-sm text-brand-purple ">Full rollback capability available after import</span>
</div>
</div>
</Card>
@@ -751,7 +751,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<h3 className="text-lg font-semibold text-[var(--purple-ink)] mb-2">
{importing ? 'Import in Progress...' : 'Ready to Import'}
</h3>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
{importing
? 'Please wait while users are imported. This may take a few minutes.'
: 'Click "Start Import" to begin importing users.'}
@@ -761,7 +761,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
{importing && (
<div className="space-y-4">
<Progress value={importProgress} className="w-full" />
<p className="text-center text-sm text-[var(--purple-lavender)]">
<p className="text-center text-sm text-brand-purple ">
{importProgress.toFixed(1)}% complete
</p>
</div>
@@ -770,7 +770,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
{!importing && !importResults && (
<Button
onClick={handleExecuteImport}
className="w-full bg-[var(--purple-lavender)] hover:bg-[var(--purple-ink)] py-6 text-lg"
className="w-full bg-brand-purple hover:bg-[var(--purple-ink)] py-6 text-lg"
>
<Play className="mr-2 h-5 w-5" />
Start Import
@@ -787,7 +787,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold text-[var(--purple-ink)] mb-2">Import Complete</h3>
<p className="text-sm text-[var(--purple-lavender)]">
<p className="text-sm text-brand-purple ">
Review the import results and download error reports if needed.
</p>
</div>
@@ -854,7 +854,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
Confirm Rollback
</DialogTitle>
</div>
<DialogDescription className="text-[var(--purple-lavender)]">
<DialogDescription className="text-brand-purple ">
This will permanently delete{' '}
<strong>{importResults?.successful_rows} users</strong> that were imported.
This action cannot be undone.
@@ -901,7 +901,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<DialogTitle className="text-2xl font-semibold text-[var(--purple-ink)]">
WordPress Import Wizard
</DialogTitle>
<DialogDescription className="text-[var(--purple-lavender)]">
<DialogDescription className="text-brand-purple ">
Import WordPress users with interactive status review and full rollback capability
</DialogDescription>
</DialogHeader>
@@ -919,7 +919,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<div
className={`
w-10 h-10 rounded-full flex items-center justify-center
${isCurrent ? 'bg-[var(--purple-lavender)] text-white' : ''}
${isCurrent ? 'bg-brand-purple text-white' : ''}
${isCompleted ? 'bg-green-600 text-white' : ''}
${!isCurrent && !isCompleted ? 'bg-gray-200 text-gray-600' : ''}
`}
@@ -962,7 +962,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
<Button
onClick={handleNext}
disabled={!canProceed()}
className="bg-[var(--purple-lavender)] hover:bg-[var(--purple-ink)]"
className="bg-brand-purple hover:bg-[var(--purple-ink)]"
>
Next
<ChevronRight className="h-4 w-4 ml-2" />
@@ -975,7 +975,7 @@ export default function WordPressImportWizard({ open, onOpenChange, onSuccess })
onOpenChange(false);
if (onSuccess) onSuccess();
}}
className="bg-[var(--purple-lavender)] hover:bg-[var(--purple-ink)]"
className="bg-brand-purple hover:bg-[var(--purple-ink)]"
>
Close
</Button>

View File

@@ -40,7 +40,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.first_name}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="first-name-input"
/>
</div>
@@ -52,7 +52,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.last_name}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="last-name-input"
/>
</div>
@@ -69,7 +69,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.phone}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="phone-input"
/>
</div>
@@ -82,7 +82,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.date_of_birth}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="dob-input"
/>
</div>
@@ -112,7 +112,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.city}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="city-input"
/>
</div>
@@ -124,7 +124,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.state}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="state-input"
/>
</div>
@@ -136,7 +136,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
required
value={formData.zipcode}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="zipcode-input"
/>
</div>
@@ -179,7 +179,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
name="partner_first_name"
value={formData.partner_first_name}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="partner-first-name-input"
/>
</div>
@@ -190,7 +190,7 @@ const RegistrationStep1 = ({ formData, setFormData, handleInputChange }) => {
name="partner_last_name"
value={formData.partner_last_name}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="partner-last-name-input"
/>
</div>

View File

@@ -36,7 +36,7 @@ const RegistrationStep2 = ({ formData, setFormData, handleInputChange }) => {
<h2 className="text-2xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Newsletter Publication Preferences *
</h2>
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Please check what information may be published in LOAF Newsletter
</p>
@@ -110,10 +110,10 @@ const RegistrationStep2 = ({ formData, setFormData, handleInputChange }) => {
value={formData.referred_by_member_name}
onChange={handleInputChange}
placeholder="Enter member name or email"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="referral-input"
/>
<p className="text-sm text-[var(--purple-lavender)] mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
If referred by a current member, you may skip the event attendance requirement.
</p>
</div>
@@ -124,7 +124,7 @@ const RegistrationStep2 = ({ formData, setFormData, handleInputChange }) => {
<h2 className="text-2xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Volunteer Interests (Optional)
</h2>
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
I may at some time be interested in volunteering with LOAF in the following ways (training is provided)
</p>
@@ -158,7 +158,7 @@ const RegistrationStep2 = ({ formData, setFormData, handleInputChange }) => {
I am requesting for scholarship
</Label>
</div>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Scholarship information is kept confidential
</p>
@@ -174,7 +174,7 @@ const RegistrationStep2 = ({ formData, setFormData, handleInputChange }) => {
onChange={handleInputChange}
placeholder="Tell us why you're requesting a scholarship..."
rows={4}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
)}

View File

@@ -27,7 +27,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
Members Directory
</h2>
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Would you like to be displayed on our private members directory? (optional and you can change the answer later)
</p>
@@ -38,7 +38,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
p-4 rounded-xl border-2 cursor-pointer transition-all
${formData.show_in_directory
? 'border-[var(--orange-light)] bg-[var(--orange-light)]/5'
: 'border-[var(--neutral-800)] hover:border-[var(--purple-lavender)]'
: 'border-[var(--neutral-800)] hover:border-brand-purple '
}
`}
onClick={() => setFormData(prev => ({ ...prev, show_in_directory: true }))}
@@ -63,7 +63,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
p-4 rounded-xl border-2 cursor-pointer transition-all
${!formData.show_in_directory
? 'border-[var(--orange-light)] bg-[var(--orange-light)]/5'
: 'border-[var(--neutral-800)] hover:border-[var(--purple-lavender)]'
: 'border-[var(--neutral-800)] hover:border-brand-purple '
}
`}
onClick={() => setFormData(prev => ({ ...prev, show_in_directory: false }))}
@@ -88,7 +88,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
{/* Conditional Directory Fields */}
{formData.show_in_directory && (
<div className="space-y-4 mt-6 p-6 bg-background rounded-xl border border-[var(--neutral-800)]">
<p className="text-[var(--purple-lavender)] text-sm" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple text-sm" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Below, choose what information you would like include in the Members Only Directory.
(If you ever want to update this information, remember the Directory Section and Account Section are separate)
</p>
@@ -101,7 +101,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
type="email"
value={formData.directory_email}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -114,7 +114,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
onChange={handleInputChange}
placeholder="Tell other members about yourself..."
rows={4}
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -125,7 +125,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
name="directory_address"
value={formData.directory_address}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -137,7 +137,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
type="tel"
value={formData.directory_phone}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -149,7 +149,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
type="date"
value={formData.directory_dob}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
@@ -162,7 +162,7 @@ const RegistrationStep3 = ({ formData, setFormData, handleInputChange }) => {
name="directory_partner_name"
value={formData.directory_partner_name}
onChange={handleInputChange}
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
/>
</div>
</div>

View File

@@ -11,7 +11,7 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
Account Credentials
</h2>
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Your email is also your username that you can use to login.
Please note you can only login after your application is validated.
</p>
@@ -28,7 +28,7 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
value={formData.email}
onChange={handleInputChange}
placeholder="your.email@example.com"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="email-input"
/>
</div>
@@ -43,10 +43,10 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
value={formData.password}
onChange={handleInputChange}
placeholder="At least 6 characters"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="password-input"
/>
<p className="text-sm text-[var(--purple-lavender)] mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-brand-purple mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Must be at least 6 characters long
</p>
</div>
@@ -60,7 +60,7 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
value={formData.confirmPassword}
onChange={handleInputChange}
placeholder="Re-enter your password"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
className="h-14 rounded-xl border-2 border-[var(--neutral-800)] focus:border-brand-purple "
data-testid="confirm-password-input"
/>
{formData.confirmPassword && formData.password !== formData.confirmPassword && (
@@ -79,7 +79,7 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
name="accepts_tos"
checked={formData.accepts_tos || false}
onChange={handleInputChange}
className="mt-1 w-4 h-4 text-[var(--purple-lavender)] border-gray-300 rounded focus:ring-[var(--purple-lavender)]"
className="mt-1 w-4 h-4 text-brand-purple border-gray-300 rounded focus:ring-brand-purple "
required
data-testid="tos-checkbox"
/>
@@ -89,7 +89,7 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
href="/become-a-member/terms-of-service"
target="_blank"
rel="noopener noreferrer"
className="text-[var(--purple-lavender)] hover:text-[var(--purple-ink)] font-semibold underline"
className="text-brand-purple hover:text-[var(--purple-ink)] font-semibold underline"
>
Terms of Service
</a>
@@ -98,7 +98,7 @@ const RegistrationStep4 = ({ formData, handleInputChange }) => {
href="become-a-member/privacy-policy"
target="_blank"
rel="noopener noreferrer"
className="text-[var(--purple-lavender)] hover:text-[var(--purple-ink)] font-semibold underline"
className="text-brand-purple hover:text-[var(--purple-ink)] font-semibold underline"
>
Privacy Policy
</a>

View File

@@ -23,14 +23,14 @@ const RegistrationStepIndicator = ({ currentStep, totalSteps = 4 }) => {
? 'bg-[var(--orange-light)] text-white scale-110 shadow-lg'
: currentStep > step.number
? 'bg-[var(--green-light)] text-white'
: 'bg-[var(--neutral-800)] text-[var(--purple-lavender)]'
: 'bg-[var(--neutral-800)] text-brand-purple '
}
`}>
{currentStep > step.number ? '✓' : step.number}
</div>
<span className={`
text-sm mt-2 font-medium transition-colors
${currentStep === step.number ? 'text-[var(--orange-light)]' : 'text-[var(--purple-lavender)]'}
${currentStep === step.number ? 'text-[var(--orange-light)]' : 'text-brand-purple '}
`} style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{step.title}
</span>
@@ -52,7 +52,7 @@ const RegistrationStepIndicator = ({ currentStep, totalSteps = 4 }) => {
</div>
{/* Step Counter */}
<p className="text-center text-[var(--purple-lavender)] mt-6 text-lg" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-center text-brand-purple mt-6 text-lg" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Step <span className="font-semibold text-[var(--orange-light)]">{currentStep}</span> of {totalSteps}
</p>
</div>

View File

@@ -1,47 +1,42 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva } from "class-variance-authority";
import { cva } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
const buttonVariants = cva("btn", {
variants: {
variant: {
default: "btn-primary",
secondary: "btn-secondary",
ghost: "btn-ghost",
outline: "btn-outline",
accent: "btn-accent",
destructive: "btn-destructive",
link: "btn-link",
},
defaultVariants: {
variant: "default",
size: "default",
size: {
default: "btn-md",
sm: "btn-sm",
lg: "btn-lg",
icon: "btn-icon",
},
}
)
},
defaultVariants: {
variant: "default",
size: "default",
},
})
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
className={cn(buttonVariants({ variant, size }), className)}
ref={ref}
{...props} />
);
{...props}
/>
)
})
Button.displayName = "Button"

View File

@@ -21,7 +21,7 @@ const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap hover:bg-[var(--lavender-300)] border-2 border-[var(--purple-lavender)] rounded-2xl px-3 py-1 text-[var(--purple-lavender)] text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-foreground data-[state=active]:text-background data-[state=active]:border-foreground data-[state=active]:shadow",
"inline-flex items-center justify-center whitespace-nowrap hover:bg-[var(--lavender-300)] border-2 border-brand-purple rounded-2xl px-3 py-1 text-brand-purple text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-foreground data-[state=active]:text-background data-[state=active]:border-foreground data-[state=active]:shadow",
className
)}
{...props}