Untitled
unknown
plain_text
a year ago
6.0 kB
10
Indexable
import React, { useEffect, useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, Modal, ScrollView } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import tailwind from 'tailwind-rn';
const tagActivityMap = {
"running": ["Tempo", "Recovery", "Hills", "Speed", "Long Run"],
"cycling": ["Hills", "Recovery", "Endurance", "Interval", "Threshold"],
"other": ["Strength", "HIIT", "Studio", "Cardio"],
};
const filterTags = (arr1, arr2) => {
const lowerCaseArr2 = arr2.map(value => value.toLowerCase());
return arr1.filter(value => !lowerCaseArr2.includes(value.toLowerCase()));
};
const processTags = (defaultTags, customTags, inputTags) => {
const uniqueTags = [...new Set([...defaultTags, ...customTags])];
return filterTags(uniqueTags, inputTags);
};
const TagSelector = ({ activityType = "running", inputTags = [], onSelect, canEdit = false, customTags = [] }) => {
const [showModal, setShowModal] = useState(false);
const [searchInput, setSearchInput] = useState('');
const [options, setOptions] = useState(processTags(tagActivityMap[activityType], customTags, inputTags));
const [filteredOptions, setFilteredOptions] = useState(options);
const [outputTags, setOutputTags] = useState(inputTags);
useEffect(() => {
if (activityType) {
const fOpt = processTags(tagActivityMap[activityType], customTags, inputTags);
setOptions(fOpt);
setFilteredOptions(fOpt);
}
}, [activityType]);
useEffect(() => {
if (inputTags) {
setOutputTags(inputTags);
if (activityType) {
const fOpt = processTags(tagActivityMap[activityType], customTags, inputTags);
setOptions(fOpt);
setFilteredOptions(fOpt);
}
}
}, [JSON.stringify(inputTags), JSON.stringify(customTags)]);
const handleSearchInputChange = (input) => {
setSearchInput(input);
const filtered = options.filter(option => option.toLowerCase().includes(input.toLowerCase()));
setFilteredOptions(filtered);
};
const addTag = (tag) => {
let newOutputTags = [...outputTags];
if (!outputTags.some(t => t.toLowerCase() === tag.toLowerCase())) {
newOutputTags.push(tag);
}
setOutputTags(newOutputTags);
const fOpts = processTags(tagActivityMap[activityType], customTags, newOutputTags);
setOptions(fOpts);
setFilteredOptions(fOpts);
onSelect(newOutputTags);
setShowModal(false);
setSearchInput('');
};
const removeTag = (tag) => {
const newOutputTags = outputTags.filter(t => t.toLowerCase() !== tag.toLowerCase());
setOutputTags(newOutputTags);
const fOpts = processTags(tagActivityMap[activityType], customTags, newOutputTags);
setOptions(fOpts);
setFilteredOptions(fOpts);
onSelect(newOutputTags);
};
const cancelModal = () => {
setShowModal(false);
setSearchInput('');
};
return (
<View className="flex-1 items-center justify-center">
<View className="w-full flex-row justify-between items-center">
<Text className="text-lg font-light text-gray-700 pr-4">Tags</Text>
<TouchableOpacity
className={`flex-1 ${canEdit && outputTags.length < 5 ? 'border border-green-400' : 'border border-gray-300'} p-2 rounded`}
onPress={() => canEdit && outputTags.length < 5 ? setShowModal(true) : null}
>
<View className="flex-row items-center justify-between">
<Text className="text-gray-600">{outputTags.length > 0 ? outputTags.join(', ') : 'Select'}</Text>
<Ionicons name="chevron-down" size={20} color="gray" />
</View>
</TouchableOpacity>
</View>
{outputTags.length > 0 && (
<View className="flex-row flex-wrap justify-end w-full pt-2">
{outputTags.map((tag, idx) => (
<TouchableOpacity
key={idx}
className={`bg-gray-200 px-2 py-1 rounded-full mr-2 mb-2 flex-row items-center ${canEdit ? '' : 'opacity-50'}`}
onPress={() => canEdit ? removeTag(tag) : null}
>
<Text className="text-sm">{tag}</Text>
{canEdit && <Ionicons name="close" size={12} color="gray" className="ml-1" />}
</TouchableOpacity>
))}
</View>
)}
<Modal visible={showModal} transparent={true} animationType="slide">
<View className="flex-1 justify-center items-center bg-white bg-opacity-85">
<View className="w-11/12 bg-white rounded-lg p-6 shadow-lg">
<TextInput
placeholder="Search or add new tag"
value={searchInput}
onChangeText={handleSearchInputChange}
className="border-b border-gray-300 mb-6 pb-2"
maxLength={20}
/>
<ScrollView className="max-h-40">
{filteredOptions.map((option, idx) => (
<TouchableOpacity key={idx} className="py-2 border-b border-gray-300" onPress={() => addTag(option)}>
<Text>{option}</Text>
</TouchableOpacity>
))}
{filteredOptions.length === 0 && (
<TouchableOpacity
className={`flex-row items-center py-2 ${searchInput ? '' : 'opacity-50'}`}
onPress={() => searchInput ? addTag(searchInput) : null}
>
<Ionicons name="add" size={20} color="gray" className="mr-2" />
<Text>Create New Tag "{searchInput}"</Text>
</TouchableOpacity>
)}
</ScrollView>
<TouchableOpacity className="mt-6 bg-gray-700 py-3 rounded-lg" onPress={cancelModal}>
<Text className="text-center text-white text-lg">Cancel</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
};
export default TagSelector;
Editor is loading...
Leave a Comment