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:
@@ -208,36 +208,36 @@ const Plans = () => {
|
||||
const breakdown = getAmountBreakdown();
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
<div className="min-h-screen bg-background">
|
||||
<Navbar />
|
||||
|
||||
<div className="max-w-7xl mx-auto px-6 py-12">
|
||||
{/* Header */}
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="text-4xl md:text-5xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<h1 className="text-4xl md:text-5xl font-semibold text-var(--purple-ink) mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
Membership Plans
|
||||
</h1>
|
||||
<p className="text-lg text-[#664fa3] max-w-2xl mx-auto" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-lg text-var(--purple-lavender) max-w-2xl mx-auto" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
Choose the membership plan that works best for you and become part of our vibrant community.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Status Banner */}
|
||||
{statusInfo && statusInfo.title && (
|
||||
<Card className="max-w-3xl mx-auto mb-8 p-6 bg-gradient-to-r from-[#f1eef9] to-[#DDD8EB]/30 border-2 border-[#664fa3]">
|
||||
<Card className="max-w-3xl mx-auto mb-8 p-6 bg-gradient-to-r from-var(--lavender-300) to-var(--neutral-800)/30 border-2 border-var(--purple-lavender)">
|
||||
<div className="flex items-start gap-4">
|
||||
<AlertCircle className="h-6 w-6 text-[#664fa3] flex-shrink-0 mt-1" />
|
||||
<AlertCircle className="h-6 w-6 text-var(--purple-lavender) flex-shrink-0 mt-1" />
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-semibold text-[#422268] mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<h3 className="text-xl font-semibold text-var(--purple-ink) mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
{statusInfo.title}
|
||||
</h3>
|
||||
<p className="text-[#664fa3] mb-4" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-var(--purple-lavender) mb-4" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
{statusInfo.message}
|
||||
</p>
|
||||
{statusInfo.action && statusInfo.actionLink && (
|
||||
<Button
|
||||
onClick={() => navigate(statusInfo.actionLink)}
|
||||
className="bg-[#664fa3] text-white hover:bg-[#422268] rounded-full"
|
||||
className="bg-var(--purple-lavender) text-white hover:bg-var(--purple-ink) rounded-full"
|
||||
>
|
||||
{statusInfo.action}
|
||||
</Button>
|
||||
@@ -249,17 +249,16 @@ const Plans = () => {
|
||||
|
||||
{loading ? (
|
||||
<div className="text-center py-20">
|
||||
<Loader2 className="h-12 w-12 text-[#664fa3] mx-auto mb-4 animate-spin" />
|
||||
<p className="text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Loading plans...</p>
|
||||
<Loader2 className="h-12 w-12 text-var(--purple-lavender) mx-auto mb-4 animate-spin" />
|
||||
<p className="text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Loading plans...</p>
|
||||
</div>
|
||||
) : plans.length > 0 ? (
|
||||
<div className={`grid gap-6 sm:gap-8 mx-auto ${
|
||||
plans.length === 1
|
||||
? 'grid-cols-1 max-w-md'
|
||||
: plans.length === 2
|
||||
<div className={`grid gap-6 sm:gap-8 mx-auto ${plans.length === 1
|
||||
? 'grid-cols-1 max-w-md'
|
||||
: plans.length === 2
|
||||
? 'grid-cols-1 sm:grid-cols-2 max-w-3xl'
|
||||
: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 max-w-5xl'
|
||||
}`}>
|
||||
}`}>
|
||||
{plans.map((plan) => {
|
||||
const minimumPrice = plan.minimum_price_cents || plan.price_cents || 3000;
|
||||
const suggestedPrice = plan.suggested_price_cents || minimumPrice;
|
||||
@@ -267,19 +266,19 @@ const Plans = () => {
|
||||
return (
|
||||
<Card
|
||||
key={plan.id}
|
||||
className="p-8 bg-white rounded-2xl border-2 border-[#ddd8eb] hover:border-[#664fa3] hover:shadow-xl transition-all"
|
||||
className="p-8 bg-background rounded-2xl border-2 border-var(--neutral-800) hover:border-var(--purple-lavender) hover:shadow-xl transition-all"
|
||||
data-testid={`plan-card-${plan.id}`}
|
||||
>
|
||||
{/* Plan Header */}
|
||||
<div className="text-center mb-6">
|
||||
<div className="bg-[#DDD8EB]/20 p-4 rounded-full w-16 h-16 mx-auto mb-4 flex items-center justify-center">
|
||||
<CreditCard className="h-8 w-8 text-[#664fa3]" />
|
||||
<div className="bg-var(--neutral-800)/20 p-4 rounded-full w-16 h-16 mx-auto mb-4 flex items-center justify-center">
|
||||
<CreditCard className="h-8 w-8 text-var(--purple-lavender)" />
|
||||
</div>
|
||||
<h2 className="text-2xl font-semibold text-[#422268] mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<h2 className="text-2xl font-semibold text-var(--purple-ink) mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
{plan.name}
|
||||
</h2>
|
||||
{plan.description && (
|
||||
<p className="text-sm text-[#664fa3] mb-4" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-sm text-var(--purple-lavender) mb-4" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
{plan.description}
|
||||
</p>
|
||||
)}
|
||||
@@ -287,22 +286,22 @@ const Plans = () => {
|
||||
|
||||
{/* Pricing */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="text-sm text-[#664fa3] mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<div className="text-sm text-var(--purple-lavender) mb-1" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
Starting at
|
||||
</div>
|
||||
<div className="text-2xl sm:text-3xl md:text-4xl font-bold text-[#422268] mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<div className="text-2xl sm:text-3xl md:text-4xl font-bold text-var(--purple-ink) mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
{formatPrice(minimumPrice)}
|
||||
</div>
|
||||
{suggestedPrice > minimumPrice && (
|
||||
<div className="text-sm text-[#664fa3] mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<div className="text-sm text-var(--purple-lavender) mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
Suggested: {formatPrice(suggestedPrice)}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
{getBillingCycleLabel(plan.billing_cycle)}
|
||||
</p>
|
||||
{plan.allow_donation && (
|
||||
<div className="mt-2 flex items-center justify-center gap-1 text-xs text-[#ff9e77]">
|
||||
<div className="mt-2 flex items-center justify-center gap-1 text-xs text-var(--orange-light)">
|
||||
<Heart className="h-3 w-3" />
|
||||
<span>Donations welcome</span>
|
||||
</div>
|
||||
@@ -312,20 +311,20 @@ const Plans = () => {
|
||||
{/* Features */}
|
||||
<div className="space-y-3 mb-8">
|
||||
<div className="flex items-start gap-3">
|
||||
<CheckCircle className="h-5 w-5 text-[#81B29A] flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-[#422268]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Access to all member events</span>
|
||||
<CheckCircle className="h-5 w-5 text-var(--green-light) flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-var(--purple-ink)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Access to all member events</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<CheckCircle className="h-5 w-5 text-[#81B29A] flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-[#422268]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Community directory access</span>
|
||||
<CheckCircle className="h-5 w-5 text-var(--green-light) flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-var(--purple-ink)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Community directory access</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<CheckCircle className="h-5 w-5 text-[#81B29A] flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-[#422268]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Exclusive member benefits</span>
|
||||
<CheckCircle className="h-5 w-5 text-var(--green-light) flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-var(--purple-ink)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Exclusive member benefits</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<CheckCircle className="h-5 w-5 text-[#81B29A] flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-[#422268]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Newsletter subscription</span>
|
||||
<CheckCircle className="h-5 w-5 text-var(--green-light) flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm text-var(--purple-ink)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Newsletter subscription</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -333,7 +332,7 @@ const Plans = () => {
|
||||
<Button
|
||||
onClick={() => handleSelectPlan(plan)}
|
||||
disabled={processingPlanId === plan.id || (statusInfo && !statusInfo.canSubscribe)}
|
||||
className="w-full bg-[#DDD8EB] text-[#422268] hover:bg-white rounded-full py-6 text-lg font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="w-full bg-var(--neutral-800) text-var(--purple-ink) hover:bg-background rounded-full py-6 text-lg font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-testid={`subscribe-button-${plan.id}`}
|
||||
>
|
||||
{processingPlanId === plan.id ? (
|
||||
@@ -353,11 +352,11 @@ const Plans = () => {
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-20">
|
||||
<CreditCard className="h-20 w-20 text-[#ddd8eb] mx-auto mb-6" />
|
||||
<h3 className="text-2xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<CreditCard className="h-20 w-20 text-var(--neutral-800) mx-auto mb-6" />
|
||||
<h3 className="text-2xl font-semibold text-var(--purple-ink) mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
No Plans Available
|
||||
</h3>
|
||||
<p className="text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
Membership plans are not currently available. Please check back later!
|
||||
</p>
|
||||
</div>
|
||||
@@ -365,17 +364,17 @@ const Plans = () => {
|
||||
|
||||
{/* Info Section */}
|
||||
<div className="mt-16 max-w-3xl mx-auto">
|
||||
<Card className="p-8 bg-gradient-to-br from-[#DDD8EB]/20 to-[#f1eef9]/20 rounded-2xl border border-[#ddd8eb]">
|
||||
<h3 className="text-xl font-semibold text-[#422268] mb-4 text-center" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<Card className="p-8 bg-gradient-to-br from-var(--neutral-800)/20 to-var(--lavender-300)/20 rounded-2xl border border-var(--neutral-800)">
|
||||
<h3 className="text-xl font-semibold text-var(--purple-ink) mb-4 text-center" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
Need Help Choosing?
|
||||
</h3>
|
||||
<p className="text-[#664fa3] text-center mb-4" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-var(--purple-lavender) text-center mb-4" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
If you have any questions about our membership plans or need assistance, please contact us.
|
||||
</p>
|
||||
<div className="text-center">
|
||||
<a
|
||||
href="mailto:support@loaf.org"
|
||||
className="text-[#ff9e77] hover:text-[#664fa3] font-medium"
|
||||
className="text-var(--orange-light) hover:text-var(--purple-lavender) font-medium"
|
||||
>
|
||||
support@loaf.org
|
||||
</a>
|
||||
@@ -388,10 +387,10 @@ const Plans = () => {
|
||||
<Dialog open={amountDialogOpen} onOpenChange={setAmountDialogOpen}>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-2xl text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
<DialogTitle className="text-2xl text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
Choose Your Amount
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<DialogDescription className="text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
{selectedPlan?.name} - {getBillingCycleLabel(selectedPlan?.billing_cycle)}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
@@ -399,11 +398,11 @@ const Plans = () => {
|
||||
<div className="space-y-6">
|
||||
{/* Amount Input */}
|
||||
<div>
|
||||
<Label htmlFor="amount" className="text-[#422268]">
|
||||
<Label htmlFor="amount" className="text-var(--purple-ink)">
|
||||
Amount (USD) *
|
||||
</Label>
|
||||
<div className="relative mt-2">
|
||||
<span className="absolute left-4 top-1/2 transform -translate-y-1/2 text-[#664fa3] text-lg font-semibold">
|
||||
<span className="absolute left-4 top-1/2 transform -translate-y-1/2 text-var(--purple-lavender) text-lg font-semibold">
|
||||
$
|
||||
</span>
|
||||
<Input
|
||||
@@ -413,25 +412,25 @@ const Plans = () => {
|
||||
min={selectedPlan ? (selectedPlan.minimum_price_cents / 100).toFixed(2) : "30.00"}
|
||||
value={amountInput}
|
||||
onChange={(e) => setAmountInput(e.target.value)}
|
||||
className="pl-8 h-14 text-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
|
||||
className="pl-8 h-14 text-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
|
||||
placeholder="50.00"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-sm text-[#664fa3] mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<p className="text-sm text-var(--purple-lavender) mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
Minimum: {selectedPlan ? formatPrice(selectedPlan.minimum_price_cents || 3000) : '$30.00'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Breakdown Display */}
|
||||
{breakdown && breakdown.total >= breakdown.base && (
|
||||
<Card className="p-4 bg-[#f9f5ff] border border-[#DDD8EB]">
|
||||
<Card className="p-4 bg-var(--lavender-400) border border-var(--neutral-800)">
|
||||
<div className="space-y-2 text-sm" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<div className="flex justify-between text-[#422268]">
|
||||
<div className="flex justify-between text-var(--purple-ink)">
|
||||
<span>Membership Fee:</span>
|
||||
<span className="font-semibold">{formatPrice(breakdown.base)}</span>
|
||||
</div>
|
||||
{breakdown.donation > 0 && (
|
||||
<div className="flex justify-between text-[#ff9e77]">
|
||||
<div className="flex justify-between text-var(--orange-light)">
|
||||
<span className="flex items-center gap-1">
|
||||
<Heart className="h-4 w-4" />
|
||||
Additional Donation:
|
||||
@@ -439,7 +438,7 @@ const Plans = () => {
|
||||
<span className="font-semibold">{formatPrice(breakdown.donation)}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-between text-[#422268] font-bold text-base pt-2 border-t border-[#DDD8EB]">
|
||||
<div className="flex justify-between text-var(--purple-ink) font-bold text-base pt-2 border-t border-var(--neutral-800)">
|
||||
<span>Total:</span>
|
||||
<span>{formatPrice(breakdown.total)}</span>
|
||||
</div>
|
||||
@@ -449,8 +448,8 @@ const Plans = () => {
|
||||
|
||||
{/* Donation Message */}
|
||||
{selectedPlan?.allow_donation && (
|
||||
<div className="bg-[#DDD8EB]/20 rounded-lg p-4">
|
||||
<p className="text-sm text-[#422268] text-center" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<div className="bg-var(--neutral-800)/20 rounded-lg p-4">
|
||||
<p className="text-sm text-var(--purple-ink) text-center" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||
<strong>Thank you for supporting our community!</strong><br />
|
||||
Your donation helps us continue our mission and provide meaningful experiences for all members.
|
||||
</p>
|
||||
@@ -470,7 +469,7 @@ const Plans = () => {
|
||||
<Button
|
||||
type="button"
|
||||
onClick={handleCheckout}
|
||||
className="flex-1 bg-[#DDD8EB] text-[#422268] hover:bg-white"
|
||||
className="flex-1 bg-var(--neutral-800) text-var(--purple-ink) hover:bg-background"
|
||||
>
|
||||
Continue to Checkout
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user