229 lines
7.7 KiB
JavaScript
229 lines
7.7 KiB
JavaScript
import React from "react";
|
|
import { StyleSheet, SafeAreaView, ImageBackground, View, ScrollView, Alert, Image, Platform } from 'react-native';
|
|
import { Title, TextInput, Button, Text, Switch } from 'react-native-paper';
|
|
import API from "../API";
|
|
import * as ImagePicker from 'expo-image-picker';
|
|
import i18n from "../i18nMessages.js";
|
|
|
|
const DefaultPhoto = "https://social.emmint.com/uploads/e6f9be6d665dc43417701bf16a90122c.png";
|
|
|
|
const NewGroup = ({ navigation }) => {
|
|
const [title, setTitle] = React.useState('');
|
|
const [subtitle, setSubtitle] = React.useState('');
|
|
const [description, setDescription] = React.useState('');
|
|
const [isPrivate, setIsPrivate] = React.useState(false);
|
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
const [selectedPhoto, setSelectedPhoto] = React.useState(null);
|
|
|
|
const pickImage = async () => {
|
|
if (isSubmitting) return;
|
|
const result = await ImagePicker.launchImageLibraryAsync({
|
|
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
|
allowsEditing: true,
|
|
aspect: [1, 1],
|
|
quality: 0.6,
|
|
});
|
|
if (!result.canceled && result.assets?.[0]) {
|
|
setSelectedPhoto(result.assets[0]);
|
|
}
|
|
};
|
|
|
|
const handleUploadPhoto = async (photo) => {
|
|
if (!photo) return '';
|
|
const uri = Platform.OS === "android" ? photo.uri : photo.uri.replace("file://", "");
|
|
const filename = photo.uri.split("/").pop() || "image.jpg";
|
|
const match = /\.(\w+)$/.exec(filename);
|
|
const ext = match?.[1] || "jpg";
|
|
const type = match ? `image/${match[1]}` : "image/jpeg";
|
|
const formData = new FormData();
|
|
formData.append("banner", {
|
|
uri,
|
|
name: `image.${ext}`,
|
|
type,
|
|
});
|
|
|
|
try {
|
|
const uploaded = await fetch("https://social.emmint.com/upload.php", {
|
|
method: "POST",
|
|
body: formData,
|
|
headers: { "Content-Type": "multipart/form-data" }
|
|
})
|
|
.then((res) => res.json())
|
|
.then((data) => data?.fileName || '');
|
|
return uploaded;
|
|
} catch (error) {
|
|
return '';
|
|
}
|
|
};
|
|
|
|
const createGroup = async () => {
|
|
const cleanTitle = title.trim();
|
|
const cleanSubtitle = subtitle.trim();
|
|
const cleanDescription = description.trim();
|
|
|
|
if (!cleanTitle) {
|
|
return Alert.alert("Missing name", "Please add a group name.");
|
|
}
|
|
if (!cleanDescription) {
|
|
return Alert.alert("Missing description", "Please add a short group description.");
|
|
}
|
|
|
|
setIsSubmitting(true);
|
|
try {
|
|
const photoPath = selectedPhoto ? await handleUploadPhoto(selectedPhoto) : '';
|
|
if (selectedPhoto && !photoPath) {
|
|
return Alert.alert("Could not upload image", "Please try again.");
|
|
}
|
|
const data = await API.newGroup(cleanTitle, cleanSubtitle, cleanDescription, isPrivate, false, photoPath);
|
|
if (data?.status !== "ok") {
|
|
return Alert.alert("Could not create group", data?.status || "Please try again.");
|
|
}
|
|
|
|
setTitle('');
|
|
setSubtitle('');
|
|
setDescription('');
|
|
setIsPrivate(false);
|
|
setSelectedPhoto(null);
|
|
|
|
if (data?._id) {
|
|
return navigation.replace("Profile", { profileid: data._id });
|
|
}
|
|
|
|
Alert.alert(
|
|
"Group created",
|
|
"Your new group is ready. You can switch to it from the menu.",
|
|
[{ text: "OK", onPress: () => navigation.goBack() }]
|
|
);
|
|
} catch (error) {
|
|
Alert.alert("Could not create group", "Please try again.");
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<SafeAreaView style={styles.safeArea}>
|
|
<ImageBackground
|
|
source={require("../assets/settings.png")}
|
|
style={styles.background}
|
|
imageStyle={styles.backgroundImage}
|
|
>
|
|
<ScrollView contentContainerStyle={styles.container}>
|
|
<Title style={styles.title}>{i18n.t("message.newGroup")}</Title>
|
|
<View style={styles.photoRow}>
|
|
<Image
|
|
source={{ uri: selectedPhoto?.uri || DefaultPhoto }}
|
|
style={styles.photoPreview}
|
|
/>
|
|
<Button mode="outlined" icon="photo" onPress={pickImage} disabled={isSubmitting}>
|
|
{selectedPhoto ? i18n.t("message.changeImage") : i18n.t("message.addGroupImage")}
|
|
</Button>
|
|
</View>
|
|
<TextInput
|
|
mode="outlined"
|
|
label={i18n.t("message.groupName")}
|
|
value={title}
|
|
onChangeText={setTitle}
|
|
style={styles.input}
|
|
/>
|
|
<TextInput
|
|
mode="outlined"
|
|
label={i18n.t("message.subtitleOptional")}
|
|
value={subtitle}
|
|
onChangeText={setSubtitle}
|
|
style={styles.input}
|
|
/>
|
|
<TextInput
|
|
mode="outlined"
|
|
label={i18n.t("message.description")}
|
|
value={description}
|
|
onChangeText={setDescription}
|
|
multiline
|
|
numberOfLines={4}
|
|
style={styles.input}
|
|
/>
|
|
<View style={styles.switchRow}>
|
|
<View style={styles.switchTextWrap}>
|
|
<Text style={styles.switchTitle}>{i18n.t("message.privateGroup")}</Text>
|
|
<Text style={styles.switchSubtitle}>{i18n.t("message.requireApprovalBeforeJoin")}</Text>
|
|
</View>
|
|
<Switch value={isPrivate} onValueChange={setIsPrivate} />
|
|
</View>
|
|
<Button
|
|
mode="contained"
|
|
onPress={createGroup}
|
|
loading={isSubmitting}
|
|
disabled={isSubmitting}
|
|
style={styles.button}
|
|
>
|
|
{i18n.t("message.createGroupAction")}
|
|
</Button>
|
|
</ScrollView>
|
|
</ImageBackground>
|
|
</SafeAreaView>
|
|
);
|
|
};
|
|
|
|
export default NewGroup;
|
|
|
|
const styles = StyleSheet.create({
|
|
safeArea: {
|
|
backgroundColor: "#edf2f7",
|
|
flex: 1,
|
|
},
|
|
background: {
|
|
flex: 1,
|
|
},
|
|
backgroundImage: {
|
|
resizeMode: "contain",
|
|
opacity: 0.05,
|
|
},
|
|
container: {
|
|
padding: 14,
|
|
paddingBottom: 24,
|
|
},
|
|
photoRow: {
|
|
alignItems: "center",
|
|
marginTop: 10,
|
|
marginBottom: 4,
|
|
},
|
|
photoPreview: {
|
|
width: 96,
|
|
height: 96,
|
|
borderRadius: 48,
|
|
marginBottom: 10,
|
|
backgroundColor: "#ddd",
|
|
},
|
|
title: {
|
|
paddingBottom: 8,
|
|
fontSize: 30,
|
|
marginTop: 8,
|
|
fontWeight: "bold",
|
|
color: "#777",
|
|
},
|
|
input: {
|
|
marginTop: 10,
|
|
backgroundColor: "#fff",
|
|
},
|
|
switchRow: {
|
|
marginTop: 16,
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
},
|
|
switchTextWrap: {
|
|
flex: 1,
|
|
},
|
|
switchTitle: {
|
|
fontSize: 16,
|
|
fontWeight: "600",
|
|
},
|
|
switchSubtitle: {
|
|
color: "#666",
|
|
marginTop: 2,
|
|
},
|
|
button: {
|
|
marginTop: 22,
|
|
},
|
|
});
|