Untitled
unknown
plain_text
a year ago
6.0 kB
6
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