- Updated Profile.js - conditional rendering with isFieldEnabled() - Updated MemberCard.js - conditional rendering for directory fields - Updated MembersDirectory.js - conditional rendering in profile dialog - Created AdminDirectorySettings.js - Admin UI for toggling fields - Updated SettingsSidebar.js - Added Directory and Registration tabs - Updated App.js - Added routes for new settings pages
190 lines
9.1 KiB
JavaScript
190 lines
9.1 KiB
JavaScript
import React from 'react'
|
|
import { Card } from './ui/card';
|
|
import { Button } from './ui/button';
|
|
import { Heart, Calendar, Mail, Phone, MapPin, Facebook, Instagram, Twitter, Linkedin, UserCircle } from 'lucide-react';
|
|
import MemberBadge from './MemberBadge';
|
|
import useDirectoryConfig from '../hooks/use-directory-config';
|
|
|
|
// Helper function to get initials
|
|
const getInitials = (firstName, lastName) => {
|
|
return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
|
|
};
|
|
|
|
// Helper function to ensure social media URLs have proper protocol
|
|
const getSocialMediaLink = (url) => {
|
|
if (!url) return null;
|
|
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
|
return `https://${url}`;
|
|
}
|
|
return url;
|
|
};
|
|
|
|
const MemberCard = ({ member, onViewProfile, tiers }) => {
|
|
const memberSince = member.member_since || member.created_at;
|
|
const { isFieldEnabled } = useDirectoryConfig();
|
|
return (
|
|
<Card className="p-6 bg-background rounded-3xl border border-[var(--neutral-800)] hover:shadow-lg transition-all h-full">
|
|
{/* Member Tier Badge */}
|
|
<div className='flex justify-end items-center mb-2'>
|
|
<MemberBadge memberSince={memberSince} tiers={tiers} />
|
|
</div>
|
|
<div className="flex justify-center mb-4">
|
|
{member.profile_photo_url ? (
|
|
<img
|
|
src={member.profile_photo_url}
|
|
alt={`${member.first_name} ${member.last_name}`}
|
|
className="w-32 h-32 rounded-full object-cover border-4 border-[var(--neutral-800)]"
|
|
/>
|
|
) : (
|
|
<div className="w-32 h-32 rounded-full bg-[var(--neutral-800)] border-4 border-[var(--neutral-800)] flex items-center justify-center">
|
|
<span className="text-4xl font-semibold text-brand-purple " style={{ fontFamily: "'Inter', sans-serif" }}>
|
|
{getInitials(member.first_name, member.last_name)}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Name */}
|
|
<h3 className="text-2xl font-semibold text-[var(--purple-ink)] text-center mb-3" style={{ fontFamily: "'Inter', sans-serif" }}>
|
|
{member.first_name} {member.last_name}
|
|
</h3>
|
|
|
|
{/* Partner Name */}
|
|
{isFieldEnabled('directory_partner_name') && member.directory_partner_name && (
|
|
<div className="flex items-center justify-center gap-2 mb-4">
|
|
<Heart className="h-4 w-4 text-[var(--orange-light)]" />
|
|
<span className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Partner: {member.directory_partner_name}
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* Bio */}
|
|
{isFieldEnabled('directory_bio') && member.directory_bio && (
|
|
<p className="text-brand-purple text-center mb-4 line-clamp-3" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
{member.directory_bio}
|
|
</p>
|
|
)}
|
|
|
|
{/* Member Since */}
|
|
{memberSince && (
|
|
<div className="flex items-center justify-center gap-2 mb-4">
|
|
<Calendar className="h-4 w-4 text-brand-purple " />
|
|
<span className="text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Member since {new Date(memberSince).toLocaleDateString('en-US', {
|
|
month: 'long',
|
|
year: 'numeric'
|
|
})}
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* Contact Information */}
|
|
<div className="space-y-3 mb-4">
|
|
{isFieldEnabled('directory_email') && member.directory_email && (
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<Mail className="h-4 w-4 text-brand-purple flex-shrink-0" />
|
|
<a
|
|
href={`mailto:${member.directory_email}`}
|
|
className="text-brand-purple hover:text-[var(--purple-ink)] truncate"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
{member.directory_email}
|
|
</a>
|
|
</div>
|
|
)}
|
|
|
|
{isFieldEnabled('directory_phone') && member.directory_phone && (
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<Phone className="h-4 w-4 text-brand-purple flex-shrink-0" />
|
|
<a
|
|
href={`tel:${member.directory_phone}`}
|
|
className="text-brand-purple hover:text-[var(--purple-ink)]"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
{member.directory_phone}
|
|
</a>
|
|
</div>
|
|
)}
|
|
|
|
{isFieldEnabled('directory_address') && member.directory_address && (
|
|
<div className="flex items-start gap-2 text-sm">
|
|
<MapPin className="h-4 w-4 text-brand-purple flex-shrink-0 mt-0.5" />
|
|
<span className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
{member.directory_address}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Social Media Links */}
|
|
{isFieldEnabled('social_media') && (member.social_media_facebook || member.social_media_instagram || member.social_media_twitter || member.social_media_linkedin) && (
|
|
<div className="pt-4 border-t border-[var(--neutral-800)]">
|
|
<div className="flex justify-center gap-3">
|
|
{member.social_media_facebook && (
|
|
<a
|
|
href={getSocialMediaLink(member.social_media_facebook)}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="p-2 rounded-lg bg-[var(--lavender-500)] hover:bg-[var(--neutral-800)] transition-colors"
|
|
title="Facebook"
|
|
>
|
|
<Facebook className="h-5 w-5 text-[var(--blue-facebook)]" />
|
|
</a>
|
|
)}
|
|
|
|
{member.social_media_instagram && (
|
|
<a
|
|
href={getSocialMediaLink(member.social_media_instagram)}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="p-2 rounded-lg bg-[var(--lavender-500)] hover:bg-[var(--neutral-800)] transition-colors"
|
|
title="Instagram"
|
|
>
|
|
<Instagram className="h-5 w-5 text-[var(--red-instagram)]" />
|
|
</a>
|
|
)}
|
|
|
|
{member.social_media_twitter && (
|
|
<a
|
|
href={getSocialMediaLink(member.social_media_twitter)}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="p-2 rounded-lg bg-[var(--lavender-500)] hover:bg-[var(--neutral-800)] transition-colors"
|
|
title="Twitter/X"
|
|
>
|
|
<Twitter className="h-5 w-5 text-[var(--blue-twitter)]" />
|
|
</a>
|
|
)}
|
|
|
|
{member.social_media_linkedin && (
|
|
<a
|
|
href={getSocialMediaLink(member.social_media_linkedin)}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="p-2 rounded-lg bg-[var(--lavender-500)] hover:bg-[var(--neutral-800)] transition-colors"
|
|
title="LinkedIn"
|
|
>
|
|
<Linkedin className="h-5 w-5 text-[var(--blue-linkedin)]" />
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* View Profile Button */}
|
|
<div className="pt-4 mt-4 border-t border-[var(--neutral-800)]">
|
|
<Button
|
|
onClick={() => onViewProfile?.(member.id)}
|
|
className="w-full bg-[var(--neutral-800)] text-[var(--purple-ink)] hover:bg-brand-purple hover:text-white rounded-full py-5"
|
|
>
|
|
<UserCircle className="h-4 w-4 mr-2" />
|
|
View Full Profile
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default MemberCard
|