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 */}
+
+ }
+ onClick={onSelectFromNetwork}
+ sx={{
+ borderRadius: 2,
+ textTransform: 'none',
+ py: 1.5,
+ px: 3,
+ borderColor: 'primary.main',
+ '&:hover': {
+ transform: 'translateY(-1px)',
+ boxShadow: theme.shadows[4],
+ },
+ }}
+ >
+ Select from your network
+
+
+ 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}
/>
)}