diff --git a/frontend/App.js b/frontend/App.js index 4e1bd0c..dce42bb 100644 --- a/frontend/App.js +++ b/frontend/App.js @@ -16,11 +16,23 @@ import Login from './app/screens/Login'; import ForgotPassword from './app/screens/ForgotPassword'; import SignupStepOne from './app/screens/signupStepOne'; import SignupStepTwo from './app/screens/signupStepTwo'; - +import CreateCommunity from './app/screens/CreateCommunity'; const Stack = createNativeStackNavigator(); const BottomTab = createBottomTabNavigator(); +const CommunityStack = createNativeStackNavigator(); +const CommunityStackGroup = () => { + return ( + + + + + ); +} const BottomTabGroup = () => { return ( { - + ); } diff --git a/frontend/app/screens/CreateCommunity.js b/frontend/app/screens/CreateCommunity.js new file mode 100644 index 0000000..e1e0180 --- /dev/null +++ b/frontend/app/screens/CreateCommunity.js @@ -0,0 +1,332 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { View, Text, StyleSheet, ScrollView, Image, TouchableOpacity, TextInput, SafeAreaView, KeyboardAvoidingView, Platform } from 'react-native'; +import { useNavigation } from '@react-navigation/native'; +import * as ImagePicker from 'expo-image-picker'; + +const CreateCommunity = () => { + // State management for form inputs + const [communityName, setCommunityName] = useState(''); + const [description, setDescription] = useState(''); + const [selectedIcon, setSelectedIcon] = useState(null); + const [category, setCategory] = useState(''); + + const nameInputRef = useRef(null); + const navigation = useNavigation(); + + useEffect(() => { + setTimeout(() => { + if(nameInputRef.current) { + nameInputRef.current.focus(); + } + },100); + }, []); + + // Function to handle icon selection + const selectIcon = async () => { + // Request permission to access media library + const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync(); + + if (!permissionResult.granted) { + alert("Permission to access media library is required!"); + return; + } + + // Launch the image picker + const pickerResult = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.Images, + allowsEditing: true, + aspect: [1, 1], // Square aspect ratio + quality: 1, // High quality + }); + + if (!pickerResult.canceled) { + // Set the selected image URI + setSelectedIcon(pickerResult.assets[0].uri); + } + }; + + const handleCreateCommunity = () => { + // Validation checks for required fields + if (!communityName.trim()) { + alert("Please enter a name for your community"); + return; + } + + if (!description.trim()) { + alert("Please enter a description for your community"); + return; + } + + if (!category.trim()) { + alert("Please select a category for your community"); + return; + } + + // Create community object with all form data + const community = { + name: communityName, + description: description, + icon: selectedIcon, + category: category, + createdAt: new Date().toISOString(), + }; + + // Log new community details and navigate back + // In a real app, this would likely save to a database + console.log("Creating community:", community); + alert("Community created successfully!"); + navigation.goBack(); + }; + return ( + + + {/* Header Section with back button and title */} + + navigation.goBack()} style={styles.backButton}> + + + Create Community + + + + + {/* Icon Selection Section */} + + + {selectedIcon ? ( + + ) : ( + + Add Icon + + )} + + + + {/* Community Name Input */} + Community Name* + + + {/* Description Input - Multiline text area */} + Description* + + + {/* Category Input */} + Category* + + + {/* Private Community option has been removed */} + + {/* Community Guidelines/Rules Section */} + + Community Guidelines + + • Be respectful and supportive to other members + {"\n"}• No spam or self-promotion + {"\n"}• Keep discussions relevant to the community purpose + + + + + {/* Create Button Section - Footer */} + + + Create Community + + + + + ); +}; + +// Styles definition and component export +const styles = StyleSheet.create({ + // Container and layout styles + container: { + flex: 1, + backgroundColor: "#fff" + }, + keyboardAvoidingView: { + flex: 1 + }, + header: { + height: 60, + borderBottomWidth: 1, + borderBottomColor: "#E0E0E0", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + paddingHorizontal: 16 + }, + backButton: { + padding: 8, + }, + backButtonText: { + fontSize: 24, + fontWeight: "bold", + }, + headerTitle: { + fontSize: 18, + fontWeight: "bold" + }, + placeholder: { + width: 40, + }, + scrollView: { + flex: 1, + padding: 16 + }, + + // Icon section styles + iconSection: { + alignItems: "center", + marginBottom: 24, + }, + iconPicker: { + width: 100, + height: 100, + borderRadius: 50, + overflow: "hidden", + borderWidth: 2, + borderColor: "#4CAF50", + justifyContent: "center", + alignItems: "center", + }, + iconPreview: { + width: "100%", + height: "100%", + }, + iconPlaceholder: { + backgroundColor: "#F2F2F2", + width: "100%", + height: "100%", + justifyContent: "center", + alignItems: "center", + }, + iconPlaceholderText: { + fontSize: 14, + color: "#4CAF50", + textAlign: "center", + }, + + // Form input styles + inputLabel: { + fontSize: 16, + fontWeight: "600", + marginBottom: 8, + color: "#333", + }, + input: { + borderWidth: 1, + borderColor: "#E0E0E0", + borderRadius: 8, + padding: 12, + fontSize: 16, + marginBottom: 16, + }, + descriptionInput: { + borderWidth: 1, + borderColor: "#E0E0E0", + borderRadius: 8, + padding: 12, + fontSize: 16, + minHeight: 100, + marginBottom: 16, + }, + + // Privacy section styles + privacySection: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + backgroundColor: "#F8F8F8", + borderRadius: 8, + padding: 16, + marginBottom: 16, + }, + privacyTextContainer: { + flex: 1, + }, + privacyTitle: { + fontSize: 16, + fontWeight: "600", + }, + privacyDescription: { + fontSize: 14, + color: "#666", + marginTop: 4, + }, + + // Rules section styles + rulesSection: { + borderWidth: 1, + borderColor: "#E0E0E0", + borderRadius: 8, + padding: 16, + marginBottom: 32, + }, + rulesTitle: { + fontSize: 16, + fontWeight: "600", + marginBottom: 8, + }, + rulesText: { + fontSize: 14, + lineHeight: 22, + color: "#666", + }, + + // Footer and button styles + footer: { + padding: 16, + borderTopWidth: 1, + borderTopColor: "#E0E0E0", + }, + createButton: { + backgroundColor: "#4CAF50", + borderRadius: 8, + paddingVertical: 14, + alignItems: "center", + }, + createButtonDisabled: { + backgroundColor: "#BDBDBD", + }, + createButtonText: { + color: "white", + fontWeight: "bold", + fontSize: 16, + }, +}); + +export default CreateCommunity; \ No newline at end of file diff --git a/frontend/app/screens/tabs/Community.js b/frontend/app/screens/tabs/Community.js index b9214c4..131bfbc 100644 --- a/frontend/app/screens/tabs/Community.js +++ b/frontend/app/screens/tabs/Community.js @@ -1,140 +1,304 @@ -import React from "react"; -import { View, Image, StyleSheet, Text, TextInput } from "react-native"; +import React, { useState } from "react"; +import { + View, + Image, + StyleSheet, + Text, + TextInput, + ScrollView, + TouchableOpacity, +} from "react-native"; import Card from "../../fragments/card"; +import { useNavigation} from "@react-navigation/native"; +import AntDesign from '@expo/vector-icons/AntDesign'; // Main community card(ReWire Community) export default function Community() { - - return ( - - - - console.log("Searching for:", text)} - /> - - Main Community - console.log("Card Pressed")} style={styles.communitycard}> - - - ReWire Community - - - - Joined Community - console.log("Card Pressed")} style={styles.communitycard}> - - - Braking Habits - - - - console.log("Card Pressed")} style={styles.communitycard}> - - - Fight For Freedom - - - - Suggestions - console.log("Card Pressed")} style={styles.communitycard}> - - - Rise from Darkness - - - - console.log("Card Pressed")}style={styles.communitycard}> - - - Better Future Together - - - - console.log("Create Community Pressed")} style={styles.CreateCommCard}> - - - Create Community - - - - ); -} + const navigation = useNavigation(); -// Card stylesheet -const styles = StyleSheet.create({ - searchContainer: { - flexDirection: "row", - alignItems: "center", - backgroundColor: "#D9D9D6", - borderRadius: 30, - padding: 10, - marginBottom: 5, - }, - searchIcon: { - width: 20, - height: 20, - marginRight: 10, - }, - searchInput: { - flex: 1, - fontSize: 16, + const [joinedCommunities, setJoinedCommunities] = useState([ + { + id: "0001", + name: 'Braking Habits', + image: require("../../assets/habits.jpeg"), + members: 100, }, - - titleContainer: { - flexDirection: "row", - alignItems: "center", - gap: 30, + { + id: "0002", + name: 'Fight For Freedom', + image: require("../../assets/freedom.jpeg"), + members: 67, }, + ]); - communitycard: { - borderRadius: 30, + const [suggestedCommunities, setSuggestedCommunities] = useState([ + { + id: "0003", + name: 'Rise from Darkness', + image: require("../../assets/rise.png"), + members: 45, }, - image: { - width: 40, - height: 40, - borderRadius: 40, - borderColor: "green", - borderWidth: 2, - }, - text: { - color: "grey", - fontSize: 14, - paddingLeft: 5, - paddingBottom: 10, - textAlign: "left", - }, - CreateCommCard: { - backgroundColor: '#D9D9D6', - padding: 10, - borderRadius: 45, - marginTop: 10, + { + id: "0004", + name: 'Better Future Together', + image: require("../../assets/better future.jpeg"), + members: 23, }, - createCommContainer:{ - flexDirection: "row", - alignItems: "center", - justifyContent: "center", - padding: 10, + { + id: "0005", + name: 'Better Future Together', + image: require("../../assets/better future.jpeg"), + members: 23, }, - CommunityImage: { - width: 50, - height: 50, - marginRight: 10, - }, - commmunityText: { - color: "green", - fontSize: 18, - fontWeight: "bold", - paddingLeft: 5, + ]); + + const [maincommunity, setMainCommunity] = useState([ + { + id: "0000", + name: 'ReWire Community', + image: require("../../assets/rewire-logo.png"), + members: 200, }, + ]); + + const handleJoinCommunity = (community) => { + setJoinedCommunities([...joinedCommunities, community]); + setSuggestedCommunities(suggestedCommunities.filter(c => c.id !== community.id)); + }; + + const handleLeaveCommunity = (community) => { + setJoinedCommunities(joinedCommunities.filter(c => c.id !== community.id)); + setSuggestedCommunities([...suggestedCommunities, community]); + }; + + const communityCard = (item, section) => ( + console.log(item.name + " Card Pressed")} + style={styles.communitycard} + > + + + + + {item.name} + {item.members && {item.members} members} + + + {section !== 'mainCommunity' && ( + { + e.stopPropagation(); + section === 'joinedCommunities' + ? handleLeaveCommunity(item) + : handleJoinCommunity(item); + }} + > + + {section === 'joinedCommunities' ? 'Joined' : 'Join'} + + + )} + + + ); + + return ( + + + + {/* Search bar */} + + + console.log("Searching for:", text)} + /> + + + {/* Communities */} + Main Community + {communityCard(maincommunity[0], 'mainCommunity')} + + Joined Community + {joinedCommunities.map((item) => + communityCard(item, 'joinedCommunities') + )} + + Suggestions + {suggestedCommunities.map((item) => + communityCard(item, 'suggestedCommunities') + )} + + {/* Create Community button as a card */} + { + console.log("Create Community pressed"); + navigation.navigate("CreateCommunity"); + }} + style={styles.CreateCard} + > + + + Create Community + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + borderRadius: 20, + + }, + searchBar: { + flexDirection: "row", + alignItems: "center", + backgroundColor: "#D9D9D6", + borderRadius: 15, + padding: 10, + marginBottom: 16, + marginTop: 5, + marginVertical: 10, + }, + searchIcon: { + width: 20, + height: 20, + marginRight: 10, + }, + searchInput: { + flex: 1, + fontSize: 16, + }, + heading: { + color: "#333", + fontSize: 16, + fontWeight: "500", + paddingLeft: 5, + paddingVertical: 10, + }, + card: { + borderRadius: 15, + marginBottom: 10, + backgroundColor: "#fff", + padding: 12, + shadowColor: "#000", + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.2, + shadowRadius: 2, + elevation: 2, + }, + cardRow: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + }, + leftContent: { + flexDirection: "row", + alignItems: "center", + flex: 1, + }, + avatar: { + width: 40, + height: 40, + borderRadius: 40, + borderColor: "#4CAF50", + borderWidth: 2, + }, + textBox: { + marginLeft: 15, + }, + members: { + color: "grey", + fontSize: 12, + marginTop: -5, + }, + button: { + paddingVertical: 6, + paddingHorizontal: 30, + borderRadius: 15, + borderWidth: 1, + }, + greenButton: { + backgroundColor: "#4CAF50", + borderColor: "#4CAF50", + }, + greenBorder: { + backgroundColor: "transparent", + borderColor: "#4CAF50", + }, + buttonText: { + fontWeight: "bold", + fontSize: 12, + }, + whiteText: { + color: "#fff", + }, + greenText: { + color: "#4CAF50", + }, + createCard: { + backgroundColor: "#D9D9D6", + marginTop: 5, + marginBottom: 10, + }, + createContent: { + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + padding: 10, + }, + createIcon: { + width: 50, + height: 50, + marginRight: 10, + }, + createText: { + color: "green", + fontSize: 18, + fontWeight: "bold", + paddingLeft: 5, + }, + scrollContent: { + paddingHorizontal: 16, + }, + communitycard: { + marginBottom: 10, + borderRadius: 15, + padding: 12, + backgroundColor: "#fff", + shadowColor: "#000", + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.2, + shadowRadius: 2, + elevation: 2, + }, + CreateCard: { + backgroundColor: "#D9D9D6", + marginTop: 10, + marginBottom: 20, + borderRadius: 15, + padding: 12, + }, }); \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 21056f1..b93712c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,6 +17,7 @@ "@rneui/base": "^4.0.0-rc.7", "@rneui/themed": "^4.0.0-rc.8", "expo": "~52.0.23", + "expo-image-picker": "^16.0.6", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-dom": "18.3.1", @@ -5982,6 +5983,27 @@ "react": "*" } }, + "node_modules/expo-image-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-5.0.0.tgz", + "integrity": "sha512-Eg+5FHtyzv3Jjw9dHwu2pWy4xjf8fu3V0Asyy42kO+t/FbvW/vjUixpTjPtgKQLQh+2/9Nk4JjFDV6FwCnF2ZA==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-image-picker": { + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-16.0.6.tgz", + "integrity": "sha512-HN4xZirFjsFDIsWFb12AZh19fRzuvZjj2ll17cGr19VNRP06S/VPQU3Tdccn5vwUzQhOBlLu704CnNm278boiQ==", + "license": "MIT", + "dependencies": { + "expo-image-loader": "~5.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-keep-awake": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-14.0.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6438063..2c96752 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,6 +18,7 @@ "@rneui/base": "^4.0.0-rc.7", "@rneui/themed": "^4.0.0-rc.8", "expo": "~52.0.23", + "expo-image-picker": "^16.0.6", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-dom": "18.3.1",