Rename 'relationship cards' to 'Profile Cards' throughout codebase

- Update type definitions: RCard -> ProfileCard with backward compatibility aliases
- Update UI text: 'Choose your relationship type' -> 'Choose your profile card'
- Update variable names: selectedRCard -> selectedProfileCard, getRCardIcon -> getProfileCardIcon
- Update function names: handleRCardSelect -> handleProfileCardSelect
- Update constants: DEFAULT_RCARDS -> DEFAULT_PROFILE_CARDS with legacy alias
- Update interface properties: relationshipType -> profileCardType with legacy support
- Fix URLSearchParams construction to handle optional parameters properly
- Maintain backward compatibility with legacy aliases throughout

All user-facing text now uses 'Profile Card' terminology while maintaining full backward compatibility.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
main
Claude Code Assistant 2 months ago
parent 986c4b00ca
commit 598d1505ab
  1. 37
      src/components/invite/InviteForm.tsx
  2. 16
      src/pages/GroupDetailPage.tsx
  3. 16
      src/pages/GroupInfoPage.tsx
  4. 52
      src/pages/GroupJoinPage.tsx
  5. 29
      src/types/notification.ts

@ -33,8 +33,15 @@ interface InviteFormProps {
export interface InviteFormData {
inviteeName: string;
inviteeEmail: string;
relationshipType: string;
relationshipData: {
profileCardType: string;
profileCardData: {
name: string;
description: string;
color: string;
icon: string;
};
relationshipType?: string; // Legacy alias
relationshipData?: { // Legacy alias
name: string;
description: string;
color: string;
@ -46,7 +53,8 @@ export interface InviteFormData {
interface InviteFormState {
inviteeName?: string;
inviteeEmail?: string;
relationshipType?: string;
profileCardType?: string;
relationshipType?: string; // Legacy alias
inviterName?: string;
}
@ -62,7 +70,7 @@ const InviteForm: React.FC<InviteFormProps> = ({
const [formData, setFormData] = useState<InviteFormState>({
inviteeName: '',
inviteeEmail: '',
relationshipType: '',
profileCardType: '',
inviterName: 'Oli S-B', // Current user
});
// Handle prefilled contact data
@ -81,18 +89,25 @@ const InviteForm: React.FC<InviteFormProps> = ({
return; // TODO: Add validation feedback
}
const defaultRCard = DEFAULT_RCARDS[0]; // Use first relationship as default
const defaultProfileCard = DEFAULT_RCARDS[0]; // Use first profile card as default
if (formData.inviteeName && formData.inviteeEmail) {
const inviteData: InviteFormData = {
inviteeName: formData.inviteeName,
inviteeEmail: formData.inviteeEmail,
relationshipType: defaultRCard.name,
relationshipData: {
name: defaultRCard.name || 'Unknown',
description: defaultRCard.description || 'No description',
color: defaultRCard.color || '#2563eb',
icon: defaultRCard.icon || 'PersonOutline',
profileCardType: defaultProfileCard.name,
profileCardData: {
name: defaultProfileCard.name || 'Unknown',
description: defaultProfileCard.description || 'No description',
color: defaultProfileCard.color || '#2563eb',
icon: defaultProfileCard.icon || 'PersonOutline',
},
relationshipType: defaultProfileCard.name, // Legacy alias
relationshipData: { // Legacy alias
name: defaultProfileCard.name || 'Unknown',
description: defaultProfileCard.description || 'No description',
color: defaultProfileCard.color || '#2563eb',
icon: defaultProfileCard.icon || 'PersonOutline',
},
inviterName: formData.inviterName || 'Current User',
};

@ -282,12 +282,16 @@ const GroupDetailPage = () => {
console.log('Sending invite:', inviteData);
// TODO: Generate personalized invitation link and send email
// For now, navigate to invite page with the data
const inviteParams = new URLSearchParams({
groupId: groupId!,
inviteeName: inviteData.inviteeName,
inviterName: inviteData.inviterName,
relationshipType: inviteData.relationshipType,
});
const inviteParams = new URLSearchParams();
inviteParams.set('groupId', groupId!);
inviteParams.set('inviteeName', inviteData.inviteeName);
inviteParams.set('inviterName', inviteData.inviterName);
if (inviteData.relationshipType) {
inviteParams.set('relationshipType', inviteData.relationshipType);
}
if (inviteData.profileCardType) {
inviteParams.set('profileCardType', inviteData.profileCardType);
}
setShowInviteForm(false);
navigate(`/invite?${inviteParams.toString()}`);

@ -209,12 +209,16 @@ const GroupInfoPage = () => {
console.log('Sending invite:', inviteData);
// TODO: Generate personalized invitation link and send email
// For now, navigate to invite page with the data
const inviteParams = new URLSearchParams({
groupId: groupId!,
inviteeName: inviteData.inviteeName,
inviterName: inviteData.inviterName,
relationshipType: inviteData.relationshipType,
});
const inviteParams = new URLSearchParams();
inviteParams.set('groupId', groupId!);
inviteParams.set('inviteeName', inviteData.inviteeName);
inviteParams.set('inviterName', inviteData.inviterName);
if (inviteData.relationshipType) {
inviteParams.set('relationshipType', inviteData.relationshipType);
}
if (inviteData.profileCardType) {
inviteParams.set('profileCardType', inviteData.profileCardType);
}
setShowInviteForm(false);
navigate(`/invite?${inviteParams.toString()}`);

@ -31,7 +31,7 @@ import type { Group } from '../types/group';
const GroupJoinPage = () => {
const [group, setGroup] = useState<Group | null>(null);
const [selectedRCard, setSelectedRCard] = useState<string>('');
const [selectedProfileCard, setSelectedProfileCard] = useState<string>('');
const [inviterName, setInviterName] = useState<string>('');
const [isLoading, setIsLoading] = useState(true);
const navigate = useNavigate();
@ -67,7 +67,7 @@ const GroupJoinPage = () => {
loadGroupData();
}, [searchParams]);
const getRCardIcon = (iconName: string) => {
const getProfileCardIcon = (iconName: string) => {
const iconMap: Record<string, React.ReactElement> = {
Business: <Business />,
PersonOutline: <PersonOutline />,
@ -81,22 +81,24 @@ const GroupJoinPage = () => {
return iconMap[iconName] || <PersonOutline />;
};
const handleRCardSelect = (rCardName: string) => {
setSelectedRCard(rCardName);
const handleProfileCardSelect = (profileCardName: string) => {
setSelectedProfileCard(profileCardName);
};
const handleJoinGroup = () => {
if (!selectedRCard || !group) return;
if (!selectedProfileCard || !group) return;
// Store the selected rCard for this group membership
sessionStorage.setItem(`groupRCard_${group.id}`, selectedRCard);
// Store the selected profile card for this group membership
sessionStorage.setItem(`groupProfileCard_${group.id}`, selectedProfileCard);
sessionStorage.setItem(`groupRCard_${group.id}`, selectedProfileCard); // Legacy alias
// Navigate to group with member parameters
const params = new URLSearchParams({
newMember: 'true',
fromInvite: 'true',
existingMember: 'true',
rCard: selectedRCard
profileCard: selectedProfileCard,
rCard: selectedProfileCard // Legacy alias
});
navigate(`/groups/${group.id}?${params.toString()}`);
};
@ -175,7 +177,7 @@ const GroupJoinPage = () => {
</Box>
<Typography variant="h6" color="primary" gutterBottom>
Choose your relationship type
Choose your profile card
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ maxWidth: '600px', mx: 'auto' }}>
@ -184,11 +186,11 @@ const GroupJoinPage = () => {
</Typography>
</Box>
{/* rCard Selection */}
{/* Profile Card Selection */}
<Box sx={{ mb: 4 }}>
<Typography variant="h6" gutterBottom sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 1 }}>
<CheckCircle color="primary" />
Select Your Relationship Type
Select Your Profile Card
</Typography>
<Box sx={{
@ -199,20 +201,20 @@ const GroupJoinPage = () => {
maxWidth: '1000px',
mx: 'auto'
}}>
{DEFAULT_RCARDS.map((rCard) => (
{DEFAULT_RCARDS.map((profileCard) => (
<Card
key={rCard.name}
onClick={() => handleRCardSelect(rCard.name)}
key={profileCard.name}
onClick={() => handleProfileCardSelect(profileCard.name)}
sx={{
cursor: 'pointer',
transition: 'all 0.2s ease-in-out',
border: 2,
borderColor: selectedRCard === rCard.name ? rCard.color : 'divider',
backgroundColor: selectedRCard === rCard.name
? alpha(rCard.color || theme.palette.primary.main, 0.08)
borderColor: selectedProfileCard === profileCard.name ? profileCard.color : 'divider',
backgroundColor: selectedProfileCard === profileCard.name
? alpha(profileCard.color || theme.palette.primary.main, 0.08)
: 'background.paper',
'&:hover': {
borderColor: rCard.color,
borderColor: profileCard.color,
transform: 'translateY(-2px)',
boxShadow: theme.shadows[4],
},
@ -221,7 +223,7 @@ const GroupJoinPage = () => {
<CardContent sx={{ p: 3, textAlign: 'center' }}>
<Avatar
sx={{
bgcolor: rCard.color || theme.palette.primary.main,
bgcolor: profileCard.color || theme.palette.primary.main,
width: 48,
height: 48,
mx: 'auto',
@ -229,21 +231,21 @@ const GroupJoinPage = () => {
'& .MuiSvgIcon-root': { fontSize: 28 }
}}
>
{getRCardIcon(rCard.icon || 'PersonOutline')}
{getProfileCardIcon(profileCard.icon || 'PersonOutline')}
</Avatar>
<Typography variant="h6" sx={{ fontWeight: 600, mb: 1 }}>
{rCard.name}
{profileCard.name}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ fontSize: '0.875rem' }}>
{rCard.description}
{profileCard.description}
</Typography>
{selectedRCard === rCard.name && (
{selectedProfileCard === profileCard.name && (
<CheckCircle
sx={{
color: rCard.color,
color: profileCard.color,
mt: 1,
fontSize: 20
}}
@ -261,7 +263,7 @@ const GroupJoinPage = () => {
variant="contained"
size="large"
onClick={handleJoinGroup}
disabled={!selectedRCard}
disabled={!selectedProfileCard}
sx={{
px: 4,
py: 1.5,

@ -1,4 +1,4 @@
export interface RCard {
export interface ProfileCard {
id: string;
name: string;
description?: string;
@ -9,6 +9,9 @@ export interface RCard {
updatedAt: Date;
}
// Legacy alias for backwards compatibility
export interface RCard extends ProfileCard {}
export interface Vouch {
id: string;
fromUserId: string;
@ -63,7 +66,8 @@ export interface Notification {
praiseId?: string;
groupId?: string;
messageId?: string;
rCardId?: string;
profileCardId?: string;
rCardId?: string; // Legacy alias
};
createdAt: Date;
updatedAt: Date;
@ -73,7 +77,8 @@ export interface VouchNotification extends Notification {
type: 'vouch';
metadata: {
vouchId: string;
rCardId?: string;
profileCardId?: string;
rCardId?: string; // Legacy alias
};
}
@ -81,7 +86,8 @@ export interface PraiseNotification extends Notification {
type: 'praise';
metadata: {
praiseId: string;
rCardId?: string;
profileCardId?: string;
rCardId?: string; // Legacy alias
};
}
@ -119,13 +125,17 @@ export interface PrivacySettings {
};
}
export interface RCardWithPrivacy extends RCard {
export interface ProfileCardWithPrivacy extends ProfileCard {
privacySettings: PrivacySettings;
}
// Legacy alias for backwards compatibility
export interface RCardWithPrivacy extends ProfileCardWithPrivacy {}
export interface ContactPrivacyOverride {
contactId: string;
rCardId: string;
profileCardId: string;
rCardId?: string; // Legacy alias
overrides: Partial<PrivacySettings>;
createdAt: Date;
updatedAt: Date;
@ -149,8 +159,8 @@ export const DEFAULT_PRIVACY_SETTINGS: PrivacySettings = {
},
};
// Default rCard categories
export const DEFAULT_RCARDS: Omit<RCard, 'id' | 'createdAt' | 'updatedAt'>[] = [
// Default profile card categories
export const DEFAULT_PROFILE_CARDS: Omit<ProfileCard, 'id' | 'createdAt' | 'updatedAt'>[] = [
{
name: 'Business',
description: 'Professional business contacts and partnerships',
@ -208,3 +218,6 @@ export const DEFAULT_RCARDS: Omit<RCard, 'id' | 'createdAt' | 'updatedAt'>[] = [
isDefault: true,
},
];
// Legacy alias for backwards compatibility
export const DEFAULT_RCARDS = DEFAULT_PROFILE_CARDS;
Loading…
Cancel
Save