diff --git a/public/community-garden-logo.svg b/public/community-garden-logo.svg new file mode 100644 index 0000000..f232a7e --- /dev/null +++ b/public/community-garden-logo.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/groups.json b/public/groups.json index 3688723..5b58db5 100644 --- a/public/groups.json +++ b/public/groups.json @@ -12,6 +12,19 @@ "tags": ["nao", "genesis", "governance", "culture", "legal", "architecture"], "image": "/naog1-butterfly-logo.svg" }, + { + "id": "8", + "name": "Anyville Community Garden", + "description": "A local community group dedicated to growing fresh produce, sharing gardening knowledge, and building neighborhood connections through sustainable urban agriculture. Join us for weekly garden workdays, seasonal harvests, and educational workshops.", + "memberCount": 32, + "memberIds": ["1", "3", "5", "7", "8", "9"], + "createdBy": "7", + "createdAt": "2023-03-15T10:00:00Z", + "updatedAt": "2024-12-20T14:30:00Z", + "isPrivate": true, + "tags": ["community", "gardening", "sustainability", "local", "education", "environment"], + "image": "/community-garden-logo.svg" + }, { "id": "1", "name": "React Developers", diff --git a/src/components/invite/InviteForm.tsx b/src/components/invite/InviteForm.tsx index 0b6ee76..0d911a9 100644 --- a/src/components/invite/InviteForm.tsx +++ b/src/components/invite/InviteForm.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Dialog, DialogTitle, @@ -10,6 +10,7 @@ import { Typography, Avatar, useTheme, + Divider, } from '@mui/material'; import { Business, @@ -19,6 +20,7 @@ import { Favorite, Home, PersonAdd, + ContactPage, } from '@mui/icons-material'; import { DEFAULT_RCARDS } from '../../types/notification'; import type { Group } from '../../types/group'; @@ -27,7 +29,12 @@ interface InviteFormProps { open: boolean; onClose: () => void; onSubmit: (inviteData: InviteFormData) => void; + onSelectFromNetwork: () => void; group: Group; + prefilledContact?: { + name: string; + email: string; + }; } export interface InviteFormData { @@ -54,7 +61,9 @@ const InviteForm: React.FC = ({ open, onClose, onSubmit, - group + onSelectFromNetwork, + group, + prefilledContact }) => { const theme = useTheme(); const [formData, setFormData] = useState({ @@ -65,6 +74,17 @@ const InviteForm: React.FC = ({ }); const [selectedRelationship, setSelectedRelationship] = useState(''); + // Handle prefilled contact data + useEffect(() => { + if (prefilledContact) { + setFormData(prev => ({ + ...prev, + inviteeName: prefilledContact.name, + inviteeEmail: prefilledContact.email + })); + } + }, [prefilledContact]); + const getRCardIcon = (iconName: string) => { const iconMap: Record = { Business: , @@ -122,6 +142,37 @@ const InviteForm: React.FC = ({ + {/* Network Selection Option */} + + + + Choose from your existing contacts to invite + + + + + + or enter manually + + + {/* Basic Info */} diff --git a/src/pages/GroupDetailPage.tsx b/src/pages/GroupDetailPage.tsx index b43c670..cce5c72 100644 --- a/src/pages/GroupDetailPage.tsx +++ b/src/pages/GroupDetailPage.tsx @@ -61,6 +61,7 @@ const GroupDetailPage = () => { const [isTyping, setIsTyping] = useState(false); const [showInviteForm, setShowInviteForm] = useState(false); const [userFirstName, setUserFirstName] = useState(); + const [selectedContact, setSelectedContact] = useState<{name: string; email: string} | undefined>(); useEffect(() => { const loadGroupData = async () => { @@ -73,7 +74,6 @@ const GroupDetailPage = () => { // Check if this is user's first visit to this group or came from invitation const hasVisitedKey = `hasVisited_group_${groupId}`; - const hasVisited = localStorage.getItem(hasVisitedKey); const fromInvite = searchParams.get('fromInvite') === 'true'; const newMember = searchParams.get('newMember') === 'true'; @@ -82,8 +82,26 @@ const GroupDetailPage = () => { if (firstName) { setUserFirstName(firstName); } + + // Handle returning from contact selection + const selectedContactName = searchParams.get('selectedContactName'); + const selectedContactEmail = searchParams.get('selectedContactEmail'); + if (selectedContactName && selectedContactEmail) { + setSelectedContact({ + name: selectedContactName, + email: selectedContactEmail + }); + setShowInviteForm(true); + + // Clean up selection parameters + const newSearchParams = new URLSearchParams(searchParams); + newSearchParams.delete('selectedContactName'); + newSearchParams.delete('selectedContactEmail'); + setSearchParams(newSearchParams); + } - if ((!hasVisited || fromInvite || newMember) && groupData) { + // Only show AI assistant automatically for new users who just joined from an invitation + if ((fromInvite || newMember) && groupData) { // Mark as visited and open AI assistant directly localStorage.setItem(hasVisitedKey, 'true'); setTimeout(() => setShowAIAssistant(true), 1000); // Small delay for better UX @@ -187,6 +205,12 @@ const GroupDetailPage = () => { navigate(`/invite?${inviteParams.toString()}`); }; + const handleSelectFromNetwork = () => { + // Navigate to contacts page with selection mode and return context + setShowInviteForm(false); + navigate(`/contacts?mode=select&returnTo=group-invite&groupId=${groupId}`); + }; + const handleStartAIAssistant = (prompt?: string) => { setInitialPrompt(prompt); setShowAIAssistant(true); @@ -916,9 +940,14 @@ const GroupDetailPage = () => { {group && ( setShowInviteForm(false)} + onClose={() => { + setShowInviteForm(false); + setSelectedContact(undefined); + }} onSubmit={handleInviteSubmit} + onSelectFromNetwork={handleSelectFromNetwork} group={group} + prefilledContact={selectedContact} /> )}