From d8c1e133ac6d3b000143d79a6461a3f06e98ff7d Mon Sep 17 00:00:00 2001 From: Koncept Kit <63216427+konceptkit@users.noreply.github.com> Date: Mon, 8 Dec 2025 14:46:16 +0700 Subject: [PATCH] Frontend Revamp --- public/index.html | 8 +- src/App.css | 22 +- src/index.css | 38 ++-- src/pages/ChangePasswordRequired.js | 30 +-- src/pages/Dashboard.js | 92 ++++----- src/pages/Events.js | 44 ++-- src/pages/ForgotPassword.js | 32 +-- src/pages/Landing.js | 302 +++++++++++++++++----------- src/pages/Login.js | 24 +-- src/pages/Plans.js | 48 ++--- src/pages/Profile.js | 56 +++--- src/pages/Register.js | 22 +- src/pages/ResetPassword.js | 30 +-- src/pages/VerifyEmail.js | 28 +-- 14 files changed, 425 insertions(+), 351 deletions(-) diff --git a/public/index.html b/public/index.html index 985a584..b823281 100644 --- a/public/index.html +++ b/public/index.html @@ -4,6 +4,12 @@ + + + + + + - Membershi Website + LOAF - Lesbians Over Age Fifty diff --git a/src/App.css b/src/App.css index 7f03c96..69893d5 100644 --- a/src/App.css +++ b/src/App.css @@ -5,28 +5,28 @@ } body { - font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', sans-serif; - background-color: #FDFCF8; - color: #3D405B; + font-family: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', sans-serif; + background-color: #FFFFFF; + color: #422268; } h1, h2, h3, h4, h5, h6 { - font-family: 'Fraunces', serif; + font-family: 'Inter', sans-serif; font-weight: 600; } -.fraunces { - font-family: 'Fraunces', serif; +.inter { + font-family: 'Inter', sans-serif; } -.dm-sans { - font-family: 'DM Sans', sans-serif; +.nunito-sans { + font-family: 'Nunito Sans', sans-serif; } -.bg-warm-gradient { - background: linear-gradient(135deg, rgba(242, 204, 143, 0.2) 0%, rgba(224, 122, 95, 0.2) 100%); +.bg-purple-gradient { + background: linear-gradient(135deg, rgba(100, 76, 159, 0.2) 0%, rgba(72, 40, 110, 0.2) 100%); } .bg-soft-mesh { - background: radial-gradient(ellipse at top right, rgba(242, 204, 143, 0.4) 0%, #FDFCF8 50%, #FDFCF8 100%); + background: radial-gradient(ellipse at top right, rgba(221, 216, 235, 0.4) 0%, #FFFFFF 50%, #FFFFFF 100%); } diff --git a/src/index.css b/src/index.css index e839749..54659d2 100644 --- a/src/index.css +++ b/src/index.css @@ -20,29 +20,29 @@ code { @layer base { :root { --background: 0 0% 100%; - --foreground: 0 0% 3.9%; + --foreground: 280 47% 27%; --card: 0 0% 100%; - --card-foreground: 0 0% 3.9%; + --card-foreground: 280 47% 27%; --popover: 0 0% 100%; - --popover-foreground: 0 0% 3.9%; - --primary: 0 0% 9%; - --primary-foreground: 0 0% 98%; - --secondary: 0 0% 96.1%; - --secondary-foreground: 0 0% 9%; - --muted: 0 0% 96.1%; - --muted-foreground: 0 0% 45.1%; - --accent: 0 0% 96.1%; - --accent-foreground: 0 0% 9%; + --popover-foreground: 280 47% 27%; + --primary: 280 47% 27%; + --primary-foreground: 0 0% 100%; + --secondary: 268 33% 89%; + --secondary-foreground: 280 47% 27%; + --muted: 268 43% 95%; + --muted-foreground: 268 35% 47%; + --accent: 17 100% 73%; + --accent-foreground: 280 47% 27%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; - --border: 0 0% 89.8%; - --input: 0 0% 89.8%; - --ring: 0 0% 3.9%; - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; + --border: 268 33% 89%; + --input: 268 33% 89%; + --ring: 268 35% 47%; + --chart-1: 268 36% 46%; + --chart-2: 17 100% 73%; + --chart-3: 268 33% 89%; + --chart-4: 280 44% 29%; + --chart-5: 268 35% 47%; --radius: 0.5rem; } .dark { diff --git a/src/pages/ChangePasswordRequired.js b/src/pages/ChangePasswordRequired.js index 5b1863d..bd9962e 100644 --- a/src/pages/ChangePasswordRequired.js +++ b/src/pages/ChangePasswordRequired.js @@ -83,19 +83,19 @@ const ChangePasswordRequired = () => { } return ( -
+
- +
- +
-

+

Password Change Required

-

+

Your password was reset by an administrator. Please create a new password to continue.

@@ -111,7 +111,7 @@ const ChangePasswordRequired = () => { value={formData.currentPassword} onChange={handleInputChange} placeholder="Enter temporary password" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" />
@@ -125,7 +125,7 @@ const ChangePasswordRequired = () => { value={formData.newPassword} onChange={handleInputChange} placeholder="Enter new password (min. 6 characters)" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" />
@@ -139,15 +139,15 @@ const ChangePasswordRequired = () => { value={formData.confirmPassword} onChange={handleInputChange} placeholder="Re-enter new password" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" />
-
+
- -
-

Password Requirements:

+ +
+

Password Requirements:

  • At least 6 characters long
  • Both passwords must match
  • @@ -159,17 +159,17 @@ const ChangePasswordRequired = () => { -
    +
    diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js index 09c7582..ecf5542 100644 --- a/src/pages/Dashboard.js +++ b/src/pages/Dashboard.js @@ -46,12 +46,12 @@ const Dashboard = () => { const getStatusBadge = (status) => { const statusConfig = { - pending_email: { icon: Clock, label: 'Pending Email', className: 'bg-[#F2CC8F] text-[#3D405B]' }, - pending_approval: { icon: Clock, label: 'Pending Approval', className: 'bg-[#A3B1C6] text-white' }, + pending_email: { icon: Clock, label: 'Pending Email', className: 'bg-orange-100 text-orange-700' }, + pending_approval: { icon: Clock, label: 'Pending Approval', className: 'bg-gray-200 text-gray-700' }, pre_approved: { icon: CheckCircle, label: 'Pre-Approved', className: 'bg-[#81B29A] text-white' }, - payment_pending: { icon: AlertCircle, label: 'Payment Pending', className: 'bg-[#E07A5F] text-white' }, + payment_pending: { icon: AlertCircle, label: 'Payment Pending', className: 'bg-orange-500 text-white' }, active: { icon: CheckCircle, label: 'Active', className: 'bg-[#81B29A] text-white' }, - inactive: { icon: AlertCircle, label: 'Inactive', className: 'bg-[#6B708D] text-white' } + inactive: { icon: AlertCircle, label: 'Inactive', className: 'bg-gray-400 text-white' } }; const config = statusConfig[status] || statusConfig.inactive; @@ -79,30 +79,30 @@ const Dashboard = () => { }; return ( -
    +
    - +
    {/* Welcome Section */}
    -

    +

    Welcome Back, {user?.first_name}!

    -

    +

    Here's an overview of your membership status and upcoming events.

    {/* Email Verification Alert */} {user && !user.email_verified && ( - +
    - +
    -

    +

    Verify Your Email Address

    -

    +

    Please verify your email address to complete your registration. Check your inbox for the verification link.

    @@ -110,7 +110,7 @@ const Dashboard = () => { onClick={handleResendVerification} disabled={resendLoading} variant="outline" - className="border-2 border-[#E07A5F] text-[#E07A5F] hover:bg-[#E07A5F] hover:text-white" + className="border-2 border-[#664fa3] text-[#664fa3] hover:bg-[#664fa3] hover:text-white" > {resendLoading ? 'Sending...' : 'Resend Verification Email'} @@ -121,22 +121,22 @@ const Dashboard = () => { )} {/* Status Card */} - +
    -

    +

    Membership Status

    {getStatusBadge(user?.status)}
    -

    +

    {getStatusMessage(user?.status)}

    {loading ? ( -

    Loading events...

    +

    Loading events...

    ) : events.length > 0 ? (
    {events.map((event) => (
    -
    - +
    +
    -

    {event.title}

    -

    +

    {event.title}

    +

    {new Date(event.start_at).toLocaleDateString()} at{' '} {new Date(event.start_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}

    -

    {event.location}

    +

    {event.location}

    @@ -217,9 +217,9 @@ const Dashboard = () => {
    ) : (
    - -

    No upcoming events at the moment.

    -

    Check back later for new events!

    + +

    No upcoming events at the moment.

    +

    Check back later for new events!

    )} @@ -227,12 +227,12 @@ const Dashboard = () => { {/* CTA Section */} {user?.status === 'pending_approval' && ( - +
    -

    +

    Application Under Review

    -

    +

    Your membership application is being reviewed by our admin team. You'll be notified once approved!

    @@ -241,20 +241,20 @@ const Dashboard = () => { {/* Payment Prompt for payment_pending status */} {user?.status === 'payment_pending' && ( - +
    - +
    -

    +

    Complete Your Payment

    -

    +

    Great news! Your membership application has been approved. Complete your payment to activate your membership and gain full access to all member benefits.

    -

    +

    Remember your password?{' '} - + Login here

    @@ -94,18 +94,18 @@ const ForgotPassword = () => {
    -

    +

    Check Your Email

    -

    - If an account exists for {email}, +

    + If an account exists for {email}, you will receive a password reset link shortly.

    -

    +

    The link will expire in 1 hour. If you don't see the email, check your spam folder.

    - diff --git a/src/pages/Landing.js b/src/pages/Landing.js index 1ff0c36..a2691c5 100644 --- a/src/pages/Landing.js +++ b/src/pages/Landing.js @@ -2,136 +2,204 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { Button } from '../components/ui/button'; import { Card } from '../components/ui/card'; -import { Calendar, Users, Heart, ArrowRight } from 'lucide-react'; -import Navbar from '../components/Navbar'; const Landing = () => { + // LOAF brand assets from Figma + const loafLogo = "https://www.figma.com/api/mcp/asset/5e3c057c-ffb0-4ceb-aa60-70a5ddbe10ab"; + const taglineImage = "https://www.figma.com/api/mcp/asset/ce184873-0c46-45eb-8480-76a9411011bf"; + const shootingStar = "https://www.figma.com/api/mcp/asset/6db528f4-493b-4560-9ff6-076bc42421ca"; + const iconMeetGreet = "https://www.figma.com/api/mcp/asset/3519deee-3f78-45e1-b537-f9c61102c18b"; + const iconSocials = "https://www.figma.com/api/mcp/asset/e95f23c6-e893-472e-a3cf-38a05290790b"; + const iconActive = "https://www.figma.com/api/mcp/asset/cab1679a-a7d6-4a5f-8732-c6c1cd578320"; + const heroLoaf = "https://www.figma.com/api/mcp/asset/f3fb05af-0fef-49b7-bc50-f5914dfe1705"; + return ( -
    - - +
    + {/* Top Header - Auth Actions */} +
    + + Register + + + Login + + +
    + + {/* Main Header - Navigation */} +
    + LOAF Logo + +
    + {/* Hero Section */} -
    -
    -
    -
    -
    -

    - Building Friendships, One Event at a Time -

    -

    - Join our vibrant community of members connecting through shared experiences, events, and meaningful relationships. -

    -
    - - - - - - -
    -
    -
    - Community members enjoying outdoor activities -
    +
    +
    +
    + LOAF +
    +
    + + + +
    +

    + LOAF is supported by the Hollyfield Foundation +

    +
    +
    + LOAF Tagline +
    +
    + + {/* About Section */} +
    +
    +

    + Welcome to LOAF +

    +
    +

    + LOAF is Houston's social networking group for lesbians who are 50 years of age and older. LOAF hosts three main activities each month, Meet and Greets, Socials, and ActiveLOAFers. TheaterLOAFers coordinate events throughout the year. +

    + Decorative element +
    + + {/* Feature Cards Section */} +
    + + Meet and Greet +
    +
    + Meet and Greet +
    +

    + The MEET and GREETs provide opportunities for prospective members to get acquainted with LOAF, have conversations with members, and ask the board of directors questions. They are held the 3rd Sunday of the month and usually take place at a restaurant or other fun places conducive to its purpose. Please email{' '} + info@loaftx.org for upcoming times and locations. +

    +
    +
    + + + Socials +
    +
    + Socials +
    +

    + Our social events provide opportunities for members to explore Houston and connect with other lesbians. Past social events include, bowling, museums, painting lessons, sporting events, Miller Outdoor Theater, bingo and board games, pool parties, putt putt golf, camping and holiday get togethers. No matter your age or ability, there is something for everyone. +

    +
    +
    + + + Active LOAFers +
    +
    + Active LOAFers +
    +

    + ActiveLOAFers events provide members with opportunities to be physically active. Past activities have included, hiking/walking in the park, swimming (or floating), pickleball, kayaking, bike riding, axe throwing, and strolling through the botanic gardens or the Arboretum. +

    +
    +
    +
    + + {/* CTA Section */} +
    +
    + + + +
    +

    + No matter your age or ability, there is something for everyone. +

    - {/* Features Section */} -
    -
    -

    - What We Offer -

    -

    - No matter your age or ability, there is something for everyone in our community. -

    -
    - -
    - -
    - + {/* Main Footer */} +
    +
    +
    + LOAF Logo +
    +
    -
    + - {/* CTA Section */} -
    -
    -

    - Ready to Join Our Community? -

    -

    - Start your membership journey today and connect with amazing people in your area. -

    - - - -
    -
    - - {/* Footer */} -
    ); diff --git a/src/pages/Login.js b/src/pages/Login.js index f8e61a1..8c6bb1b 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -54,23 +54,23 @@ const Login = () => { }; return ( -
    +
    - +
    - + Back to Home
    - +
    -

    +

    Welcome Back

    -

    +

    Login to access your member dashboard.

    @@ -86,7 +86,7 @@ const Login = () => { value={formData.email} onChange={handleInputChange} placeholder="your.email@example.com" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="login-email-input" />
    @@ -94,7 +94,7 @@ const Login = () => {
    - + Forgot password?
    @@ -105,7 +105,7 @@ const Login = () => { value={formData.password} onChange={handleInputChange} placeholder="Enter your password" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="login-password-input" />
    @@ -113,16 +113,16 @@ const Login = () => { -

    +

    Don't have an account?{' '} - + Register here

    diff --git a/src/pages/Plans.js b/src/pages/Plans.js index 9dd22e7..e969e97 100644 --- a/src/pages/Plans.js +++ b/src/pages/Plans.js @@ -66,43 +66,43 @@ const Plans = () => { }; return ( -
    +
    {/* Header */}
    -

    +

    Membership Plans

    -

    +

    Choose the membership plan that works best for you and become part of our vibrant community.

    {loading ? (
    - -

    Loading plans...

    + +

    Loading plans...

    ) : plans.length > 0 ? (
    {plans.map((plan) => ( {/* Plan Header */}
    -
    - +
    +
    -

    +

    {plan.name}

    {plan.description && ( -

    +

    {plan.description}

    )} @@ -110,10 +110,10 @@ const Plans = () => { {/* Pricing */}
    -
    +
    {formatPrice(plan.price_cents)}
    -

    +

    {getBillingCycleLabel(plan.billing_cycle)}

    @@ -122,19 +122,19 @@ const Plans = () => {
    - Access to all member events + Access to all member events
    - Community directory access + Community directory access
    - Exclusive member benefits + Exclusive member benefits
    - Newsletter subscription + Newsletter subscription
    @@ -142,7 +142,7 @@ const Plans = () => {
    ) : (
    - -

    + +

    No Plans Available

    -

    +

    Membership plans are not currently available. Please check back later!

    @@ -171,17 +171,17 @@ const Plans = () => { {/* Info Section */}
    - -

    + +

    Need Help Choosing?

    -

    +

    If you have any questions about our membership plans or need assistance, please contact us.

    support@loaf.org diff --git a/src/pages/Profile.js b/src/pages/Profile.js index 4277806..979b2b4 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -69,52 +69,52 @@ const Profile = () => { if (!profileData) { return ( -
    +
    -

    Loading profile...

    +

    Loading profile...

    ); } return ( -
    +
    - +
    -

    +

    My Profile

    -

    +

    Update your personal information below.

    - + {/* Read-only Information */} -
    -

    - +
    +

    + Account Information

    -

    Email

    -

    {profileData.email}

    +

    Email

    +

    {profileData.email}

    -

    Status

    -

    {profileData.status.replace('_', ' ')}

    +

    Status

    +

    {profileData.status.replace('_', ' ')}

    -

    Role

    -

    {profileData.role}

    +

    Role

    +

    {profileData.role}

    -

    Date of Birth

    -

    +

    Date of Birth

    +

    {new Date(profileData.date_of_birth).toLocaleDateString()}

    @@ -125,7 +125,7 @@ const Profile = () => { type="button" onClick={() => setPasswordDialogOpen(true)} variant="outline" - className="border-2 border-[#E07A5F] text-[#E07A5F] hover:bg-[#FFF3E0] rounded-full px-6 py-3" + className="border-2 border-[#664fa3] text-[#664fa3] hover:bg-[#f1eef9] rounded-full px-6 py-3" > Change Password @@ -135,7 +135,7 @@ const Profile = () => { {/* Editable Form */}
    -

    +

    Personal Information

    @@ -147,7 +147,7 @@ const Profile = () => { name="first_name" value={formData.first_name} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="first-name-input" />
    @@ -158,7 +158,7 @@ const Profile = () => { name="last_name" value={formData.last_name} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="last-name-input" />
    @@ -172,7 +172,7 @@ const Profile = () => { type="tel" value={formData.phone} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="phone-input" />

    @@ -184,7 +184,7 @@ const Profile = () => { name="address" value={formData.address} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="address-input" />
    @@ -197,7 +197,7 @@ const Profile = () => { name="city" value={formData.city} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="city-input" />
    @@ -208,7 +208,7 @@ const Profile = () => { name="state" value={formData.state} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="state-input" />
    @@ -219,7 +219,7 @@ const Profile = () => { name="zipcode" value={formData.zipcode} onChange={handleInputChange} - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" data-testid="zipcode-input" />
    @@ -228,7 +228,7 @@ const Profile = () => {
    -

    +

    Already have an account?{' '} - + Login here

    diff --git a/src/pages/ResetPassword.js b/src/pages/ResetPassword.js index 561b836..22c2e1d 100644 --- a/src/pages/ResetPassword.js +++ b/src/pages/ResetPassword.js @@ -63,19 +63,19 @@ const ResetPassword = () => { }; return ( -
    +
    - +
    -
    - +
    +
    -

    +

    Reset Password

    -

    +

    Enter your new password below.

    @@ -91,7 +91,7 @@ const ResetPassword = () => { value={formData.newPassword} onChange={handleInputChange} placeholder="Enter new password (min. 6 characters)" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" />
    @@ -105,15 +105,15 @@ const ResetPassword = () => { value={formData.confirmPassword} onChange={handleInputChange} placeholder="Re-enter new password" - className="h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]" + className="h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" />
    -
    +
    - -
    -

    Password Requirements:

    + +
    +

    Password Requirements:

    • At least 6 characters long
    • Both passwords must match
    • @@ -125,15 +125,15 @@ const ResetPassword = () => { -

      +

      Remember your password?{' '} - + Login here

      diff --git a/src/pages/VerifyEmail.js b/src/pages/VerifyEmail.js index 762666a..890b35b 100644 --- a/src/pages/VerifyEmail.js +++ b/src/pages/VerifyEmail.js @@ -37,18 +37,18 @@ const VerifyEmail = () => { }, [token]); return ( -
      +
      - +
      - + {status === 'loading' && ( <> - -

      + +

      Verifying Your Email...

      -

      +

      Please wait while we verify your email address.

      @@ -57,18 +57,18 @@ const VerifyEmail = () => { {status === 'success' && ( <> -

      +

      Email Verified Successfully!

      -

      +

      {message}

      -

      +

      Next steps: Attend an event and meet a board member within 90 days. Once you've attended an event, our admin team will review your application.