expo-app/src/Components/Modal/index.js

399 lines
10 KiB
JavaScript

import { useContext, useEffect, useState } from "react";
import { AppContext, AppStyles, IsPlatformIos } from "../../utils";
import {
KeyboardAvoidingView,
Modal,
ScrollView,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
import { Divider } from "../Divider";
import MyIcon from "../Icon";
import { useTranslation } from "react-i18next";
/*
transparent: set this to prevent modal reopening on iOS
https://github.com/facebook/react-native/issues/34018
*/
const modalContentStyle = { margin: 10, paddingTop: 10 };
export default function MyModal({
children,
isOpen,
closeModal,
header,
content,
disableAnimationForIos,
scrollView,
}) {
const appContext = useContext(AppContext);
const getContent = () => {
if (scrollView) {
return (
<ScrollView>
<View style={modalContentStyle}>{content}</View>
</ScrollView>
);
}
return <View style={modalContentStyle}>{content}</View>;
};
return (
<View>
<Modal
visible={isOpen}
animationType={
disableAnimationForIos && IsPlatformIos() ? "none" : "slide"
}
onRequestClose={() => closeModal()}
transparent
>
{children}
<View
style={[
{
flex: 1,
backgroundColor: appContext.appTheme.backgroundColor,
paddingTop: IsPlatformIos() ? 30 : 15,
},
,
]}
>
{header}
{getContent()}
</View>
</Modal>
</View>
);
}
export function MyDefaultModalHeader({ title, closeModal }) {
const appContext = useContext(AppContext);
return (
<View
style={{
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<TouchableOpacity onPress={() => closeModal()}>
<MyIcon name="chevron-left" size={24} style={{ marginLeft: 20 }} />
</TouchableOpacity>
<Text
style={[
AppStyles.typography16,
{ fontWeight: "bold", color: appContext.appTheme.text },
]}
>
{title}
</Text>
<View style={{ marginRight: 40 }} />
</View>
);
}
export function MyPickerModalListItem({ onPress, itemName, itemSelected }) {
const appContext = useContext(AppContext);
return (
<>
<TouchableOpacity onPress={onPress}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginLeft: 10,
marginRight: 10,
}}
>
<Text
style={[
AppStyles.typography16,
{ color: appContext.appTheme.text },
]}
>
{itemName}
</Text>
{itemSelected && (
<MyIcon
name="check"
size={24}
color={appContext.appTheme.colors.primary}
/>
)}
</View>
</TouchableOpacity>
<Divider />
</>
);
}
export function MyPickerModal({ isOpen, setIsOpen, items, searchFilter }) {
const appContext = useContext(AppContext);
const { t } = useTranslation();
const [providedItems, setProvidedItems] = useState([]);
const [searchFilterInput, setSearchFilterInput] = useState("");
useEffect(() => setProvidedItems(items), [items]);
const closeModal = () => {
setIsOpen(false);
setProvidedItems(items);
setSearchFilterInput("");
};
return (
<Modal
visible={isOpen}
animationType="slide"
onRequestClose={() => closeModal()}
>
<KeyboardAvoidingView
behavior={IsPlatformIos() ? "padding" : "height"}
style={[
{
flex: 1,
backgroundColor: appContext.appTheme.backgroundColor,
},
]}
>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TouchableOpacity onPress={() => closeModal()}>
<MyIcon
name={searchFilter ? "chevron-left" : "window-close"}
size={24}
style={{ marginLeft: 20, marginTop: 20, marginBottom: 20 }}
color={appContext.appTheme.icon}
/>
</TouchableOpacity>
{searchFilter && (
<View
style={{
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
borderBottomWidth: 1,
borderColor: appContext.appTheme.textInputBottomColor,
marginLeft: 10,
marginRight: 10,
}}
>
<MyIcon
style={{ marginLeft: 10 }}
name="magnify"
size={22}
color={appContext.appTheme.icon}
/>
<TextInput
style={{
flex: 1,
height: 40,
marginLeft: 10,
marginRight: 10,
}}
placeholder={t("common.textInputPlaceholderSearch")}
value={searchFilterInput}
onChangeText={(text) => {
setSearchFilterInput(text);
setProvidedItems(() =>
items.filter((provItem) => {
return provItem.label
.toLowerCase()
.startsWith(text.toLowerCase());
})
);
}}
/>
{searchFilterInput !== "" && (
<TouchableOpacity
onPress={() => {
setSearchFilterInput("");
setProvidedItems(items);
}}
>
<MyIcon
style={{ marginRight: 10 }}
name="close"
size={20}
color={appContext.appTheme.icon}
/>
</TouchableOpacity>
)}
</View>
)}
</View>
{providedItems.length === 0 && (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<MyIcon
name="magnify-remove-outline"
color={appContext.appTheme.icon}
size={64}
/>
<Text style={[AppStyles.typography20, { marginTop: 20 }]}>
{t("common.pickerSearchFilterNoResults")}
</Text>
</View>
)}
{providedItems.map((item, i) => {
return item.selected ? (
<View key={i}>
<TouchableOpacity onPress={() => closeModal()}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginLeft: 20,
marginRight: 20,
}}
>
<Text
style={[
AppStyles.typography16,
{ color: appContext.appTheme.text },
]}
>
{item.label}
</Text>
<MyIcon
name="check"
size={24}
color={appContext.appTheme.colors.primary}
/>
</View>
</TouchableOpacity>
<Divider />
</View>
) : (
<View key={i}>
<TouchableOpacity
onPress={() => {
closeModal();
item.onPress();
}}
>
<Text
style={[
AppStyles.typography16,
{ marginLeft: 20, color: appContext.appTheme.text },
]}
>
{item.label}
</Text>
</TouchableOpacity>
<Divider />
</View>
);
})}
</KeyboardAvoidingView>
</Modal>
);
}
export function MyTextInputModal({
isOpen,
setIsOpen,
onTextInputSave,
modalTitle,
inputTitle,
inputDescription,
}) {
const appContext = useContext(AppContext);
const closeModal = () => setIsOpen(false);
return (
<Modal
visible={isOpen}
animationType="slide"
onRequestClose={() => closeModal()}
>
<View
style={[
{
flex: 1,
backgroundColor: appContext.appTheme.backgroundColor,
},
]}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
marginTop: 20,
}}
>
<TouchableOpacity onPress={() => closeModal()}>
<MyIcon
name="chevron-left"
size={24}
style={{ marginLeft: 20 }}
color={appContext.appTheme.icon}
/>
</TouchableOpacity>
<Text style={AppStyles.typography20}>{modalTitle}</Text>
<TouchableOpacity
onPress={() => {
closeModal();
onTextInputSave();
}}
>
<MyIcon
name="check"
size={24}
style={{ marginRight: 20 }}
color={appContext.appTheme.colors.primary}
/>
</TouchableOpacity>
</View>
<View
style={{
flex: 1,
padding: 20,
}}
>
<Text style={{ color: "gray" }}>{inputTitle}</Text>
<TextInput
style={{
height: 40,
borderBottomWidth: 1,
borderColor: appContext.appTheme.textInputBottomColor,
}}
value="Turtle"
/>
<Text
style={[AppStyles.typography14, { color: "gray", marginTop: 6 }]}
>
{inputDescription}
</Text>
</View>
</View>
</Modal>
);
}