| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- import React, { useState } from 'react';
- import {
- View,
- StyleSheet,
- ScrollView,
- TouchableOpacity,
- ActivityIndicator,
- Text,
- Image
- } from 'react-native';
- import ActionSheet, { SheetManager } from 'react-native-actions-sheet';
- import * as yup from 'yup';
- import * as ImagePicker from 'expo-image-picker';
- import { chatStyles } from './styles';
- import { Colors } from 'src/theme';
- import { AvatarWithInitials, Input } from 'src/components';
- import Checkbox from 'expo-checkbox';
- import CameraIcon from 'assets/icons/messages/camera.svg';
- import { API_HOST } from 'src/constants';
- import { FlashList } from '@shopify/flash-list';
- import { Formik } from 'formik';
- import { useNavigation } from '@react-navigation/native';
- import { usePostUpdateGroupSettingsMutation, usePostRemoveFromGroupMutation } from '@api/chat';
- import { getFontSize } from 'src/utils';
- import CheckSvg from 'assets/icons/travels-screens/circle-check.svg';
- import { StoreType, storage } from 'src/storage';
- const SettingsSchema = yup.object({
- name: yup
- .string()
- .required('name is required')
- .min(3, 'group name should be at least 3 characters'),
- description: yup.string().optional().max(8000, 'description should not exceed 8000 characters')
- });
- const SearchModal = () => {
- const currentUserId = storage.get('uid', StoreType.STRING) as number;
- const [isSubmitting, setIsSubmitting] = useState(false);
- const [data, setData] = useState<any>(null);
- const [image, setImage] = useState<ImagePicker.ImagePickerAsset | null>(null);
- const { mutateAsync: editGroup } = usePostUpdateGroupSettingsMutation();
- const { mutateAsync: removeFromGroup } = usePostRemoveFromGroupMutation();
- const [canEdit, setCanEdit] = useState(false);
- const [canSend, setCanSend] = useState(false);
- const [canAdd, setCanAdd] = useState(false);
- const [canSee, setCanSee] = useState(false);
- const [filteredUsers, setFilteredUsers] = useState<any[]>([]);
- const handleSheetOpen = (payload: any) => {
- setData(payload);
- setCanEdit(payload?.settings.members_can_edit_settings === 1);
- setCanSend(payload?.settings.members_can_send_messages === 1);
- setCanAdd(payload?.settings.members_can_add_new_members === 1);
- setCanSee(payload?.settings.members_can_see_members === 1);
- setFilteredUsers(payload?.members ?? []);
- };
- const pickImage = async () => {
- let result = await ImagePicker.launchImageLibraryAsync({
- mediaTypes: ImagePicker.MediaTypeOptions.Images,
- allowsEditing: true,
- aspect: [4, 4],
- quality: 1
- });
- if (!result.canceled) {
- setImage(result.assets[0]);
- }
- };
- const toggleUserSelection = (user: any) => {
- const isSelected = filteredUsers.some((selected) => selected.uid === user.uid);
- if (isSelected) {
- setFilteredUsers((prev) => prev.filter((selected) => selected.uid !== user.uid));
- } else {
- setFilteredUsers((prev) => [...prev, user]);
- }
- };
- const renderUserItem = ({ item }: { item: any }) => {
- const isSelected = filteredUsers.some((selected) => selected.uid === item.uid);
- return (
- <TouchableOpacity
- style={styles.userItem}
- disabled={item.uid === +currentUserId}
- onPress={() => toggleUserSelection(item)}
- >
- {item.avatar ? (
- <Image source={{ uri: API_HOST + item.avatar }} style={styles.avatar} />
- ) : (
- <AvatarWithInitials
- text={item.name?.split(' ')[0][0] + (item.name?.split(' ')[1][0] ?? '')}
- flag={API_HOST + item?.flag1}
- size={36}
- fontSize={16}
- borderColor={Colors.LIGHT_GRAY}
- borderWidth={1}
- />
- )}
- <View style={styles.userDetails}>
- <Text style={styles.userName}>{item.name}</Text>
- </View>
- {item.admin === 1 && (
- <Text
- style={{
- fontSize: getFontSize(10),
- fontWeight: '600',
- color: Colors.LIGHT_GRAY
- }}
- >
- Admin
- </Text>
- )}
- {item.uid !== +currentUserId && (
- <View style={styles.unselectedCircle}>
- {isSelected && <CheckSvg fill={Colors.DARK_BLUE} height={20} width={20} />}
- </View>
- )}
- </TouchableOpacity>
- );
- };
- return (
- <ActionSheet
- id="edit-group-modal"
- containerStyle={styles.sheetContainer}
- defaultOverlayOpacity={0.5}
- closeOnTouchBackdrop={false}
- keyboardHandlerEnabled={false}
- onBeforeShow={(sheetRef) => {
- const payload = sheetRef || null;
- handleSheetOpen(payload);
- }}
- onClose={() => {
- setImage(null);
- data && data.refetch();
- }}
- >
- <Formik
- validationSchema={SettingsSchema}
- initialValues={{
- name: data?.settings?.name ?? '',
- description: data?.settings?.description ?? ''
- }}
- onSubmit={async (values) => {
- if (!data) return;
- setIsSubmitting(true);
- const removedUsers = data?.members
- ?.filter((member: any) => !filteredUsers.some((user) => user.uid === member.uid))
- ?.map((member: any) => member.uid);
- const groupData: any = {
- token: data.token,
- group_token: data.groupToken,
- name: values.name,
- description: values.description,
- members_can_edit_settings: canEdit ? 1 : 0,
- members_can_send_messages: canSend ? 1 : 0,
- members_can_add_new_members: canAdd ? 1 : 0,
- members_can_see_members: canSee ? 1 : 0
- };
- if (image && image.uri) {
- groupData.group_avatar = {
- type: image.type || 'image',
- uri: image.uri,
- name: image.uri.split('/').pop()!
- };
- }
- if (removedUsers.length > 0) {
- await Promise.all(
- removedUsers.map(
- async (userId: number) =>
- await removeFromGroup(
- {
- token: data.token,
- group_token: data.groupToken,
- uid: userId
- },
- {
- onSuccess: () => {
- data && data.refetchMembers();
- }
- }
- )
- )
- );
- }
- await editGroup(groupData, {
- onSuccess: () => {
- setIsSubmitting(false);
- setTimeout(() => {
- data && data.setCacheKey(Date.now());
- }, 2500);
- SheetManager.hide('edit-group-modal');
- },
- onError: () => {
- setIsSubmitting(false);
- }
- });
- }}
- >
- {(props) => {
- return (
- <View style={chatStyles.container}>
- <View style={chatStyles.header}>
- <TouchableOpacity
- onPress={() => SheetManager.hide('edit-group-modal')}
- style={styles.backButton}
- >
- <Text style={chatStyles.headerText}>Back</Text>
- </TouchableOpacity>
- {isSubmitting ? (
- <ActivityIndicator size="small" color={Colors.DARK_BLUE} style={styles.loader} />
- ) : (
- <TouchableOpacity onPress={() => props.handleSubmit()} style={styles.saveButton}>
- <Text style={chatStyles.headerText}>Save</Text>
- </TouchableOpacity>
- )}
- </View>
- <ScrollView
- showsVerticalScrollIndicator={false}
- style={{ flex: 1 }}
- contentContainerStyle={{ gap: 16 }}
- >
- <View style={styles.photoContainer}>
- <TouchableOpacity onPress={pickImage} style={chatStyles.photoContainer}>
- {image || data?.settings?.avatar ? (
- <>
- <Image
- source={{
- uri: image
- ? image.uri
- : `${API_HOST}${data?.settings?.avatar}?cacheBust=${data?.cacheKey}`
- }}
- style={styles.groupPhotoImage}
- />
- <Text style={chatStyles.photoText}>Change photo</Text>
- </>
- ) : (
- <>
- <View
- style={[chatStyles.groupPhoto, { backgroundColor: Colors.FILL_LIGHT }]}
- >
- <CameraIcon width={36} height={36} fill={Colors.LIGHT_GRAY} />
- </View>
- <Text style={chatStyles.photoText}>Add photo</Text>
- </>
- )}
- </TouchableOpacity>
- </View>
- <Input
- placeholder="Add group name"
- value={props.values.name}
- inputMode="text"
- onChange={props.handleChange('name')}
- onBlur={props.handleBlur('name')}
- header="Group name"
- formikError={props.touched.name && (props.errors.name as string)}
- />
- <Input
- placeholder="Add group description"
- value={props.values.description}
- onChange={props.handleChange('description')}
- onBlur={props.handleBlur('description')}
- header="Description"
- multiline
- height={58}
- formikError={props.touched.description && (props.errors.description as string)}
- />
- <View>
- <Text style={chatStyles.title}>Members can</Text>
- <View style={chatStyles.optionsContainer}>
- <TouchableOpacity
- style={chatStyles.option}
- onPress={() => setCanEdit(!canEdit)}
- >
- <Text style={chatStyles.optionText}>Edit group settings</Text>
- <Checkbox
- value={canEdit}
- color={Colors.DARK_BLUE}
- style={{ backgroundColor: Colors.WHITE, borderRadius: 4 }}
- onValueChange={() => setCanEdit(!canEdit)}
- />
- </TouchableOpacity>
- <TouchableOpacity
- style={chatStyles.option}
- onPress={() => setCanSend(!canSend)}
- >
- <Text style={chatStyles.optionText}>Send messages</Text>
- <Checkbox
- value={canSend}
- color={Colors.DARK_BLUE}
- style={{ backgroundColor: Colors.WHITE, borderRadius: 4 }}
- onValueChange={() => setCanSend(!canSend)}
- />
- </TouchableOpacity>
- <TouchableOpacity style={chatStyles.option} onPress={() => setCanAdd(!canAdd)}>
- <Text style={chatStyles.optionText}>Add new members</Text>
- <Checkbox
- value={canAdd}
- color={Colors.DARK_BLUE}
- style={{ backgroundColor: Colors.WHITE, borderRadius: 4 }}
- onValueChange={() => setCanAdd(!canAdd)}
- />
- </TouchableOpacity>
- <TouchableOpacity style={chatStyles.option} onPress={() => setCanSee(!canSee)}>
- <Text style={chatStyles.optionText}>See members</Text>
- <Checkbox
- value={canSee}
- color={Colors.DARK_BLUE}
- style={{ backgroundColor: Colors.WHITE, borderRadius: 4 }}
- onValueChange={() => setCanSee(!canSee)}
- />
- </TouchableOpacity>
- </View>
- </View>
- {data?.settings?.admin === 1 ? (
- <View>
- <Text style={chatStyles.title}>Members: {data?.members?.length}</Text>
- {data?.members?.length > 0 && (
- <FlashList
- viewabilityConfig={{
- waitForInteraction: true,
- itemVisiblePercentThreshold: 50,
- minimumViewTime: 1000
- }}
- data={data?.members || []}
- renderItem={renderUserItem}
- keyExtractor={(item) => item.uid.toString()}
- estimatedItemSize={100}
- extraData={filteredUsers}
- showsVerticalScrollIndicator={false}
- contentContainerStyle={{ paddingBottom: 16 }}
- />
- )}
- </View>
- ) : null}
- </ScrollView>
- </View>
- );
- }}
- </Formik>
- </ActionSheet>
- );
- };
- const styles = StyleSheet.create({
- sheetContainer: {
- height: '95%',
- borderTopLeftRadius: 15,
- borderTopRightRadius: 15,
- paddingHorizontal: 16
- },
- backButton: {
- paddingVertical: 16,
- paddingHorizontal: 6
- },
- saveButton: {
- paddingVertical: 16,
- paddingHorizontal: 6
- },
- loader: {
- padding: 10
- },
- groupPhotoImage: {
- width: 80,
- height: 80,
- borderRadius: 40,
- borderWidth: 1,
- borderColor: Colors.FILL_LIGHT
- },
- errorBorder: {
- borderColor: Colors.RED,
- borderWidth: 1
- },
- photoContainer: {
- alignItems: 'center',
- gap: 8
- },
- userDetails: {
- flex: 1
- },
- userName: {
- color: Colors.DARK_BLUE,
- fontSize: getFontSize(14),
- fontFamily: 'montserrat-700'
- },
- userSubtitle: {
- color: Colors.DARK_BLUE,
- fontSize: 14,
- fontFamily: 'montserrat-500'
- },
- userItem: {
- flexDirection: 'row',
- alignItems: 'center',
- paddingVertical: 8,
- paddingHorizontal: 12,
- backgroundColor: Colors.FILL_LIGHT,
- gap: 8,
- borderRadius: 8,
- marginBottom: 6
- },
- avatar: {
- width: 36,
- height: 36,
- borderRadius: 18,
- borderWidth: 1,
- borderColor: Colors.LIGHT_GRAY
- },
- unselectedCircle: {
- width: 20,
- height: 20,
- borderRadius: 10,
- borderWidth: 1,
- borderColor: Colors.LIGHT_GRAY,
- justifyContent: 'center',
- alignItems: 'center'
- }
- });
- export default SearchModal;
|