react-native-paper#IconButton JavaScript Examples

The following examples show how to use react-native-paper#IconButton. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: profile-card.js    From MediBuddy with MIT License 6 votes vote down vote up
export default function profileCard({
  name,
  avatar,

  onSelected,
  disableRightBtn,
}) {
  const LeftContent = props => (
    <Avatar.Image
      {...props}
      source={{
        uri: avatar,
      }}
    />
  );
  const RightContent = props => (
    <IconButton
      icon="arrow-right"
      color="#0097e8"
      size={20}
      onPress={onSelected}
      style={{ marginBottom: 24 }}
    />
  );
  return (
    <Card.Title
      title={name}
      subtitle="View profile"
      left={LeftContent}
      right={disableRightBtn ? null : RightContent}
      titleStyle={styles.cardTitle}
      subtitleStyle={styles.cardSub}
    />
  );
}
Example #2
Source File: LoadingButton.js    From Legacy with Mozilla Public License 2.0 6 votes vote down vote up
export default function () {
  var dispatch = useDispatch();
  var loading = useSelector(i=>i.loading>0);
  var theme = useSelector(i=>i.themes[i.theme]);
  return (
    loading ? <View style={{width:48,justifyContent:"center"}}><ActivityIndicator size="small" color={theme.navigation.fg} /></View> : <IconButton
      onPress={() => dispatch(r.refresh())}
      color={theme.navigation.fg}
      icon="refresh"
    />
  )
}
Example #3
Source File: SHCPro.js    From Legacy with Mozilla Public License 2.0 6 votes vote down vote up
function DateSwitcher({ dateString }) {
  var moment = useMoment();
  const nav = useNavigation();
  const theme = useSelector(i=>i.themes[i.theme]);
  const [datePickerOpen,setDatePickerOpen] = React.useState(false);
  return <View style={{ padding: 4, width: 400, maxWidth: "100%", alignSelf: "center" }}>
    <Card cardStyle={{ backgroundColor: (theme.clanCardHeader || theme.navigation).bg }} noPad>
      <View style={{ flexDirection: "row", alignItems: "center" }}>
        <Menu
          visible={datePickerOpen}
          onDismiss={() => setDatePickerOpen(false)}
          anchor={
            <IconButton icon="calendar" color={(theme.clanCardHeader || theme.navigation).fg} onPress={() => setDatePickerOpen(true)} />
          }
          contentStyle={{ padding: 0, backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border, width: 300 }}
        >
          <DatePicker noWrap value={moment({
            year: Number(dateString.split('-')[0]),
            month: Number(dateString.split('-')[1]) - 1,
            date: Number(dateString.split('-')[2]),
          })} onChange={(date) => {
            nav.setParams({
              date: `${date.year()}-${(date.month() + 1).toString().padStart(2, '0')}-${(date.date()).toString().padStart(2, '0')}`
            })
          }} />
        </Menu>

        <Text allowFontScaling={false} style={{ flex: 1, ...font("bold"), fontSize: 16, color: (theme.clanCardHeader || theme.navigation).fg }}>{moment({
          year: Number(dateString.split('-')[0]),
          month: Number(dateString.split('-')[1]) - 1,
          date: Number(dateString.split('-')[2]),
        }).format('L')}</Text>
      </View>
    </Card>
  </View>
}
Example #4
Source File: SHCLite.js    From Legacy with Mozilla Public License 2.0 6 votes vote down vote up
function DateSwitcher({ dateString }) {
  var moment = useMoment();
  const nav = useNavigation();
  const theme = useSelector(i=>i.themes[i.theme]);
  const [datePickerOpen,setDatePickerOpen] = React.useState(false);
  return <View style={{ padding: 4, width: 400, maxWidth: "100%", alignSelf: "center" }}>
    <Card cardStyle={{ backgroundColor: (theme.clanCardHeader || theme.navigation).bg }} noPad>
      <View style={{ flexDirection: "row", alignItems: "center" }}>
        <Menu
          visible={datePickerOpen}
          onDismiss={() => setDatePickerOpen(false)}
          anchor={
            <IconButton icon="calendar" color={(theme.clanCardHeader || theme.navigation).fg} onPress={() => setDatePickerOpen(true)} />
          }
          contentStyle={{ padding: 0, backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border, width: 300 }}
        >
          <DatePicker noWrap value={moment({
            year: Number(dateString.split('-')[0]),
            month: Number(dateString.split('-')[1]) - 1,
            date: Number(dateString.split('-')[2]),
          })} onChange={(date) => {
            nav.setParams({
              date: `${date.year()}-${(date.month() + 1).toString().padStart(2, '0')}-${(date.date()).toString().padStart(2, '0')}`
            })
          }} />
        </Menu>

        <Text allowFontScaling={false} style={{ flex: 1, ...font("bold"), fontSize: 16, color: (theme.clanCardHeader || theme.navigation).fg }}>{moment({
          year: Number(dateString.split('-')[0]),
          month: Number(dateString.split('-')[1]) - 1,
          date: Number(dateString.split('-')[2]),
        }).format('L')}</Text>
      </View>
    </Card>
  </View>
}
Example #5
Source File: POI.js    From Legacy with Mozilla Public License 2.0 6 votes vote down vote up
function DateSwitcher({ dateString }) {
  var moment = useMoment();
  const nav = useNavigation();
  const theme = useSelector(i=>i.themes[i.theme]);
  const [datePickerOpen,setDatePickerOpen] = React.useState(false);
  return <View style={{ padding: 4, width: 400, maxWidth: "100%", alignSelf: "center" }}>
    <Card cardStyle={{ backgroundColor: (theme.clanCardHeader || theme.navigation).bg }} noPad>
      <View style={{ flexDirection: "row", alignItems: "center" }}>
        <Menu
          visible={datePickerOpen}
          onDismiss={() => setDatePickerOpen(false)}
          anchor={
            <IconButton icon="calendar" color={(theme.clanCardHeader || theme.navigation).fg} onPress={() => setDatePickerOpen(true)} />
          }
          contentStyle={{ padding: 0, backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border, width: 300 }}
        >
          <DatePicker noWrap value={moment({
            year: Number(dateString.split('-')[0]),
            month: Number(dateString.split('-')[1]) - 1,
            date: Number(dateString.split('-')[2]),
          })} onChange={(date) => {
            nav.setParams({
              date: `${date.year()}-${(date.month() + 1).toString().padStart(2, '0')}-${(date.date()).toString().padStart(2, '0')}`
            })
          }} />
        </Menu>

        <Text allowFontScaling={false} style={{ flex: 1, ...font("bold"), fontSize: 16, color: (theme.clanCardHeader || theme.navigation).fg }}>{moment({
          year: Number(dateString.split('-')[0]),
          month: Number(dateString.split('-')[1]) - 1,
          date: Number(dateString.split('-')[2]),
        }).format('L')}</Text>
      </View>
    </Card>
  </View>
}
Example #6
Source File: Page.js    From Legacy with Mozilla Public License 2.0 6 votes vote down vote up
function DateSwitcher({ dateString, toggleDrawer }) {
  var moment = useMoment();
  const nav = useNavigation();
  const theme = useSelector(i => i.themes[i.theme]);
  const [datePickerOpen, setDatePickerOpen] = React.useState(false);
  return <View style={{ ...(theme.page_content.border ? { borderBottomWidth: 1, borderBottomColor: theme.page_content.border } : {}), borderTopLeftRadius: 8, borderTopRightRadius: 8, backgroundColor: (theme.clanCardHeader || theme.navigation).bg }}>
    <View style={{ flexDirection: "row", alignItems: "center" }}>
      <Menu
        visible={datePickerOpen}
        onDismiss={() => setDatePickerOpen(false)}
        anchor={
          <IconButton icon="calendar" color={(theme.clanCardHeader || theme.navigation).fg} onPress={() => setDatePickerOpen(true)} />
        }
        contentStyle={{ padding: 0, backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border, width: 300 }}
      >
        <DatePicker noWrap value={moment({
          year: Number(dateString.split('-')[0]),
          month: Number(dateString.split('-')[1]) - 1,
          date: Number(dateString.split('-')[2]),
        })} onChange={(date) => {
          nav.setParams({
            date: `${date.year()}-${(date.month() + 1).toString().padStart(2, '0')}-${(date.date()).toString().padStart(2, '0')}`
          })
        }} />
      </Menu>

      <Text allowFontScaling={false} style={{ flex: 1, ...font("bold"), fontSize: 16, color: (theme.clanCardHeader || theme.navigation).fg }}>{moment({
        year: Number(dateString.split('-')[0]),
        month: Number(dateString.split('-')[1]) - 1,
        date: Number(dateString.split('-')[2]),
      }).format('L')}</Text>
      {toggleDrawer && <IconButton icon="filter" color={(theme.clanCardHeader || theme.navigation).fg} onPress={() => toggleDrawer()} />}
    </View>
  </View>
}
Example #7
Source File: Colour.js    From Legacy with Mozilla Public License 2.0 6 votes vote down vote up
function DateSwitcher({ dateString }) {
  var moment = useMoment();
  const nav = useNavigation();
  const theme = useSelector(i=>i.themes[i.theme]);
  const [datePickerOpen,setDatePickerOpen] = React.useState(false);
  return <View style={{ padding: 4, width: 400, maxWidth: "100%", alignSelf: "center" }}>
    <Card cardStyle={{ backgroundColor: (theme.clanCardHeader || theme.navigation).bg }} noPad>
      <View style={{ flexDirection: "row", alignItems: "center" }}>
        <Menu
          visible={datePickerOpen}
          onDismiss={() => setDatePickerOpen(false)}
          anchor={
            <IconButton icon="calendar" color={(theme.clanCardHeader || theme.navigation).fg} onPress={() => setDatePickerOpen(true)} />
          }
          contentStyle={{ padding: 0, backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border, width: 300 }}
        >
          <DatePicker noWrap value={moment({
            year: Number(dateString.split('-')[0]),
            month: Number(dateString.split('-')[1]) - 1,
            date: Number(dateString.split('-')[2]),
          })} onChange={(date) => {
            nav.setParams({
              date: `${date.year()}-${(date.month() + 1).toString().padStart(2, '0')}-${(date.date()).toString().padStart(2, '0')}`
            })
          }} />
        </Menu>

        <Text allowFontScaling={false} style={{ flex: 1, ...font("bold"), fontSize: 16, color: (theme.clanCardHeader || theme.navigation).fg }}>{moment({
          year: Number(dateString.split('-')[0]),
          month: Number(dateString.split('-')[1]) - 1,
          date: Number(dateString.split('-')[2]),
        }).format('L')}</Text>
      </View>
    </Card>
  </View>
}
Example #8
Source File: Search.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function SearchScreen({ navigation }) {
  var {t} = useTranslation();
  var theme = useSelector(i=>i.themes[i.theme])
  var input = React.useRef();
  var [value,setValue] = React.useState('');
  var [search,setSearch] = React.useState('');
  var [timeoutC,setTimeoutC] = React.useState(null);
  function onValue(val) {
    if(timeoutC) clearTimeout(timeoutC)
    setValue(val);
    setTimeoutC(setTimeout(() => {
      return setSearch(val);
    }, 500))
  }
  var dispatch = useDispatch();
  var userBookmarks = useSelector(i => i.userBookmarks);
  function addUser(user) {
    dispatch(userBookmarksR(userBookmarks.concat([user])));
  }
  function removeUser(user) {
    dispatch(userBookmarksR(userBookmarks.filter(i=>i.user_id!=user.user_id)));
  }
  
  var reqData = {
    endpoint: 'user/find',
    data: {text:search}
  }
  var users = useSelector(i => i.request_data[stringify(reqData)] ?? {})
  useFocusEffect(
    React.useCallback(() => {
      if(search.length>=3) dispatch(request.add(reqData))
      return () => {
        if(search.length>=3) dispatch(request.remove(reqData))
      };
    }, [search])
  );
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{padding:4,width:"100%"}}>
        <Card noPad cardStyle={{flexDirection: "row", backgroundColor: "#fff", alignItems:"stretch"}}>
          <TextInput
            onSubmitEditing={()=>setSearch(value)}
            ref={input}
            style={{ paddingHorizontal: 8, flex: 1, borderRadius: 8, borderBottomLeftRadius: 8, height: 40 }}
            onChangeText={onValue}
            value={value}
            returnKeyType="search"
          />
          {/* <IconButton onPress={()=>setSearch(value)} style={{backgroundColor: theme.navigation.bg}} icon="magnify" color={theme.navigation.fg} /> */}
        </Card>
      </View>
      <View style={{padding:4}}>
        <Card noPad>
          <View>
            {search.length<3&&<Text allowFontScaling={false} style={{textAlign:"center",...font("bold"),fontSize:16,color:theme.page_content.fg}}>{t('search:user')}</Text>}
            {search.length>=3&&!users?.data?.users&&<View style={{height:100,justifyContent:"center",alignItems:"center"}}>
              <ActivityIndicator size={32} color={theme.page_content.fg} />
            </View>}
            {users?.data?.users?.length===0&&<Text allowFontScaling={false} style={{textAlign:"center",...font("bold"),fontSize:16,color:theme.page_content.fg}}>{t('search:empty')}</Text>}
            {users?.data?.users?.slice?.(0,20)?.map?.(i=><View key={i.clan_id} style={{padding: 4, flexDirection: "row", alignItems: "center"}}>
              {!userBookmarks.find(x=>x.user_id==i.user_id)&&<IconButton size={24} onPress={()=>addUser(i)} icon="bookmark-plus" color="#016930" />}
              {!!userBookmarks.find(x=>x.user_id==i.user_id)&&<IconButton size={24} onPress={()=>removeUser(i)} icon="bookmark-minus" color="#ff2222" />}
              <Image style={{height:24,width:24,marginRight:8,marginLeft:-8,borderRadius:12}} source={{uri:i.avatar??`https://munzee.global.ssl.fastly.net/images/avatars/ua${Number(i.user_id).toString(36)}.png`}} />
              <View style={{flex:1}}>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:16,color:theme.page_content.fg}}>{i.username}</Text>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:12,color:theme.page_content.fg}}>#{i.user_id}</Text>
              </View>
              <IconButton size={24} onPress={()=>navigation.navigate('UserDetails',{ username: i.username })} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
          </View>
        </Card>
      </View>
    </ScrollView>
  );
}
Example #9
Source File: NavigationStack.js    From MediBuddy with MIT License 5 votes vote down vote up
function App() {
  const stackProps = DeviceInfo.isTablet() ? { headerMode: 'none' } : {};

  return (
    <NavigationContainer ref={navigationRef}>
      <Stack.Navigator
        {...stackProps}
        screenOptions={{
          headerStyle: {
            backgroundColor: '##fff',
            borderBottomWidth: StyleSheet.hairlineWidth,
          },
          headerTintColor: '#2c3e50',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
          headerBackTitleVisible: false,
        }}>
        <Stack.Screen name="Login" component={Login} />
        <Stack.Screen
          name="Home"
          component={Tabs}
          options={{
            headerLeft: null,
            headerRight: () => (
              <View style={{ flexDirection: 'row' }}>
                <IconButton
                  icon="settings"
                  color="#bdc3c7"
                  size={20}
                  onPress={() => {}}
                />
                <IconButton
                  icon="bell"
                  color="#bdc3c7"
                  size={20}
                  onPress={() => {}}
                />
              </View>
            ),
          }}
        />
        <Stack.Screen
          name="AppointmentDetail"
          component={AppointmentDetail}
          options={{ title: 'Appointment Information' }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
Example #10
Source File: tab-bar.js    From MediBuddy with MIT License 5 votes vote down vote up
CustomIcon = ({ name, onPress }) => {
  return (
    <IconButton icon={name} color="#bdc3c7" size={28} onPress={() => {}} />
  );
}
Example #11
Source File: section-item.js    From MediBuddy with MIT License 5 votes vote down vote up
function SectionItem({ icon, name, color }) {
  return (
    <View style={styles.section}>
      <IconButton icon={icon} color={color} size={20} onPress={() => {}} />
      <Text style={styles.name}>{name}</Text>
    </View>
  );
}
Example #12
Source File: CustomCommandItem.js    From react-native-nfc-rewriter with MIT License 5 votes vote down vote up
function CommandItem(props) {
  const {cmd, resp, onDelete, onEdit, readOnly, onMoveUp, onMoveDown} = props;
  const wrapperStyle = {
    marginBottom: 10,
    padding: 5,
    borderRadius: 2,
    backgroundColor: 'white',
  };

  let innerElem = null;

  if (cmd.type === 'command') {
    innerElem = (
      <View style={{flex: 1}}>
        <Text style={{marginRight: 5, color: 'gray'}}>TRANSCEIVE</Text>
        <PrettyCommandPayloadBytes bytes={cmd.payload} />
        {Array.isArray(resp) && (
          <>
            <Text style={{marginRight: 5, color: 'gray'}}>RESPONSE</Text>
            <PrettyCommandPayloadBytes bytes={resp} />
          </>
        )}
      </View>
    );
  } else {
    innerElem = (
      <>
        <Text style={{marginRight: 5, color: 'gray'}}>
          {cmd.type.toUpperCase()}
        </Text>
        <Text style={{flex: 1}}>{cmd.payload}</Text>
      </>
    );
  }

  return (
    <View style={[wrapperStyle, {flexDirection: 'row', alignItems: 'center'}]}>
      {innerElem}

      {!readOnly && (
        <IconButton
          disabled={!onMoveUp}
          icon={() => (
            <View style={{transform: [{rotateZ: '270deg'}]}}>
              <Icon name="chevron-right" size={22} />
            </View>
          )}
          onPress={onMoveUp}
        />
      )}

      {!readOnly && (
        <IconButton
          disabled={!onMoveDown}
          icon={() => (
            <View style={{transform: [{rotateZ: '90deg'}]}}>
              <Icon name="chevron-right" size={22} />
            </View>
          )}
          onPress={onMoveDown}
        />
      )}

      {!readOnly && (
        <IconButton
          icon={() => <Icon name="edit" size={22} />}
          onPress={onEdit}
        />
      )}

      {!readOnly && (
        <IconButton
          icon={() => <Icon name="delete" size={22} />}
          onPress={onDelete}
        />
      )}
    </View>
  );
}
Example #13
Source File: index.js    From puente-reactnative-collect with MIT License 5 votes vote down vote up
AssetFormSelect = ({ setSelectedForm, surveyingOrganization }) => {
  const [assetForms, setAssetForms] = useState([]);
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    setLoading(true);
    assetFormsQuery(surveyingOrganization).then((forms) => {
      setLoading(false);
      setAssetForms(forms);
    });
  }, []);

  const refreshAssetForms = async () => {
    setLoading(true);
    await assetFormsQuery(surveyingOrganization).then((forms) => {
      setAssetForms(forms);
      setLoading(false);
    });
  };

  const selectForm = (form) => {
    setSelectedForm(form);
  };

  return (
    <View>
      <View style={{ flexDirection: 'row' }}>
        <Text style={styles.header}>{I18n.t('assetFormSelect.supAssetForms')}</Text>
        <IconButton
          style={{ bottom: 7 }}
          color={theme.colors.primary}
          size={20}
          icon="refresh"
          onPress={refreshAssetForms}
        />
      </View>
      {loading
        && <ActivityIndicator />}
      <ScrollView horizontal style={styles.componentContainer}>
        {assetForms && assetForms.map((form) => (
          <Card
            key={form.objectId}
            style={layout.cardSmallStyle}
            onPress={() => selectForm(form)}
          >
            <View style={styles.cardContainer}>
              <View style={styles.textContainer}>
                <Text style={styles.text}>
                  {form.name}
                </Text>
              </View>
            </View>
          </Card>
        ))}
      </ScrollView>
    </View>
  );
}
Example #14
Source File: Page.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function CalendarScreen() {
  var moment = useMoment()
  var theme = useSelector(i=>i.themes[i.theme]);
  var [month,setMonth] = React.useState(moment().month())
  var [year,setYear] = React.useState(moment().year())

  function add() {
    if(month==11) {
      setMonth(0);
      setYear(year+1);
    } else {
      setMonth(month+1)
    }
  }
  function remove() {
    if(month==0) {
      setMonth(11);
      setYear(year-1);
    } else {
      setMonth(month-1)
    }
  }

  var [type,setType] = React.useState('default');

  return (
    <View style={{backgroundColor:theme.page.bg,flex:1,padding:4,justifyContent:"center",alignItems:"center"}}>
      <View style={{width:"100%",maxWidth:400}}>
        <Card noFlex noPad={true}>
          <View style={{flexDirection:"column"}}>
            <View style={{borderTopLeftRadius:8,borderTopRightRadius:8,flexDirection:"row",alignItems:"center",backgroundColor:(theme.clanCardHeader||theme.navigation).bg}}>
              <IconButton icon={type=="default"?"format-text":"view-grid"} color={(theme.clanCardHeader||theme.navigation).fg} onPress={()=>setType(type=="default"?"alt":"default")}/>
              <IconButton icon="chevron-left" color={(theme.clanCardHeader||theme.navigation).fg} onPress={remove}/>
              <Text allowFontScaling={false} style={{flex:1,textAlign:"center",color:(theme.clanCardHeader||theme.navigation).fg}}>{moment({month,year}).format('MMMM YYYY')}</Text>
              <IconButton icon="chevron-right" color={(theme.clanCardHeader||theme.navigation).fg} onPress={add}/>
            </View>
            <Calendar month={month} year={year} theme={theme} type={type}/>
          </View>
        </Card>
      </View>
    </View>
  );
}
Example #15
Source File: Bouncers.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function SearchScreen({ navigation }) {
  var {t} = useTranslation();
  var moment = useMoment();
  var theme = useSelector(i => i.themes[i.theme])
  function hasChild(cat) {
    return !!categories.find(i => i.parents.includes(cat.id));
  }
  var data = useAPIRequest({
    endpoint: 'bouncers/overview/v1',
    cuppazee: true
  })
  function get(i) {
    var x = 0;
    for(var icon of [i.icon,...i.alt_icons||[]]) {
      x = (data||{})[`https://munzee.global.ssl.fastly.net/images/pins/${icon}.png`]||x;
    }
    return x;
  }
  return (
    <ScrollView
      contentContainerStyle={{ width: 800, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      {Object.entries(data||{}).filter(i=>!getType(i[0])).length>0&&<View style={{ padding: 4 }}>
        <Card noPad>
          <View>
            <View style={{flexDirection:"row",justifyContent:"center",alignItems:"center"}}>
              <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 24, color: theme.page_content.fg, paddingVertical: 4, textAlign: "center" }}>Uncategorised</Text>
              {/* <IconButton icon="map" color={theme.page_content.fg} onPress={()=>navigation.navigate("BouncerMap",{type:cdata.id})} /> */}
            </View>
            <View style={{flexDirection:"row",flexWrap:"wrap",justifyContent:"center"}}>
              {Object.entries(data||{}).filter(i=>!getType(i[0])).map(i => <TouchableRipple>
                <View key={i.id} style={{ padding: 4, width: 80, alignItems: "center", opacity: i[1]>0?1:0.4 }}>
                  <Image style={{ height: 32, width: 32, marginHorizontal: 8 }} source={getIcon(i[0])} />
                  <Text allowFontScaling={false} numberOfLines={1} ellipsizeMode="middle" style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{i[0].replace(/https:\/\/munzee.global.ssl.fastly.net\/images\/pins\/(.+)\.png/,'$1')}</Text>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{i[1].toString()}</Text>
                </View>
              </TouchableRipple>)}
            </View>
          </View>
        </Card>
      </View>}
      {[...categories.filter(i=>i.seasonal&&i.seasonal.starts<Date.now()&&i.seasonal.ends>Date.now()),...categories.filter(i => i.parents.includes('bouncer')),...categories.filter(i => i.id=="temppob_other"),...categories.filter(i => i.id=="temppob_evo"),...categories.filter(i => i.id=="scatter")].filter(i => !hasChild(i)).filter(i=>!i.hidden&&i.id!="bouncerhost").map(cdata=><View style={{ padding: 4 }}>
        <Card noPad>
          <View>
            <View style={{flexDirection:"row",justifyContent:"center",alignItems:"center"}}>
              <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 24, color: theme.page_content.fg, paddingVertical: 4, textAlign: "center" }}>{cdata.name}</Text>
              <IconButton icon="map" color={theme.page_content.fg} onPress={()=>navigation.navigate("BouncerMap",{type:cdata.id})} />
            </View>
            {cdata?.seasonal && <>
              {/* <Text allowFontScaling={false} style={{...font("bold"),fontSize:20,color:theme.page_content.fg,textAlign:"center"}}>{category_data.id}</Text> */}
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{moment(cdata.seasonal.starts).format('L LT')} - {moment(cdata.seasonal.ends).format('L LT')}</Text>
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{t('bouncers:duration',{duration:moment.duration(moment(cdata.seasonal.starts).diff(moment(cdata.seasonal.ends))).humanize()})}</Text>
            </>}
            <View style={{flexDirection:"row",flexWrap:"wrap",justifyContent:"center"}}>
              {types.filter(i => i.category === cdata.id).filter(i=>!i.hidden&&!i.capture_only).map(i => <TouchableRipple onPress={()=>navigation.navigate("BouncerMap",{type:i.icon})}>
                <View key={i.id} style={{ padding: 4, width: 80, alignItems: "center", opacity: get(i)>0?1:0.4 }}>
                  <Image style={{ height: 32, width: 32, marginHorizontal: 8 }} source={getIcon(i.custom_icon ?? i.icon)} />
                  <Text allowFontScaling={false} numberOfLines={1} ellipsizeMode="middle" style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{i.name}</Text>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{get(i).toString()}</Text>
                </View>
              </TouchableRipple>)}
            </View>
          </View>
        </Card>
      </View>)}
    </ScrollView>
  );
}
Example #16
Source File: Auth.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function AuthScreen({route}) {
  var { t } = useTranslation();
  var theme = useSelector(i => i.themes[i.theme]);
  var [status, setStatus] = React.useState(0);
  const navigation = useNavigation();
  const discovery = {
    authorizationEndpoint: 'https://api.munzee.com/oauth',
    tokenEndpoint: 'https://api.munzee.com/oauth/login',
  };
  const data = useAPIRequest({
    endpoint: 'competition/join/v1',
    cuppazee: true,
    data: {
      username: route.params.username
    }
  })
  const config = data?.team === "pear" ? config_pear : config_pine;

  const [request, response, promptAsync] = AuthSession.useAuthRequest(
    {
      clientId: config.client_id,
      scopes: ['read'],
      redirectUri: config.redirect_uri,
      state: JSON.stringify({
        redirect: Oconfig.redirect_uri,
        platform: Platform.OS
      })
    },
    discovery
  );

  React.useEffect(() => {
    if (response) {
      (async function () {
        if (!response.params || !response.params.teaken) return setStatus("invalid_response");
        if(response.params.status) {
          setStatus(`success_${response.params.status}`);
        } else {
          setStatus("success");
        }
      })()
    }
  }, [response]);
  if (status === "loading") {
    return <View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: theme.page_content.bg }}>
      <ActivityIndicator size="large" color={theme.page_content.fg} />
    </View>
  }
  if (status === "success" || status === "success_reopt" || status === "success_already") {
    return <View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: theme.page_content.bg }}>
      {status !== "success_already" && <>
        <Image source={data?.team === "pine" ? require('assets/pine.png') : require('assets/pear.png')} style={{ height: 128, width: 128, borderRadius: 8, marginBottom: 16 }} />
        <Text allowFontScaling={false} style={{ fontSize: 16, fontWeight: "bold", textAlign: "center", color: theme.page_content.fg }}>{response.params.username} {status === "success" ? "has joined" : "is in"} Team {data?.team.toUpperCase() || '???¿??'}</Text>
      </>}
      <Button mode="contained" onPress={()=>navigation.replace('CompetitionHome')}>Return to Competition Dashboard</Button>
    </View>
  }
  return <View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: theme.page_content.bg }}>
    {!!status && <>
      {statusIcons[status]==="loading"?<ActivityIndicator size="large" color={theme.page_content.fg} />:<MaterialCommunityIcons name={statusIcons[status]} color={theme.page.fg} size={48} />}
      <Text allowFontScaling={false} style={{ fontSize: 16, fontWeight: "bold", textAlign: "center", color: theme.page_content.fg }}>{statusMessages[status]}</Text>
    </>}
    <Text allowFontScaling={false} style={{ color: theme.page_content.fg, fontSize: 24 }}>Opt-in to Competition</Text>
    <Text allowFontScaling={false} style={{ color: theme.page_content.fg, fontSize: 16 }}>{t('auth:tap')}</Text>
    <IconButton
      disabled={!data || (status && status !== "invalid_response")}
      size={32}
      onPress={() => {
        setStatus("waiting_for_login");
        promptAsync({
          useProxy: Oconfig.useProxy,
          redirectUri: config.redirect_uri
        });
      }}
      color={theme.page_content.fg}
      icon="login-variant"
    />
  </View>
}
Example #17
Source File: Category.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function SearchScreen({ navigation, route }) {
  var { t } = useTranslation();
  var moment = useMoment();
  var category = route.params.category;
  var theme = useSelector(i => i.themes[i.theme])
  var category_data = categories.find(i => i.id == category);
  var parent_datas = categories.filter(i => category_data.parents.includes(i.id));
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{ padding: 4 }}>
        <Card noPad>
          <View>
            {parent_datas.map(parent_data => parent_data.id !== "root" ? <View style={{ padding: 4, flexDirection: "row", alignItems: "center" }}>
              <IconButton size={24} onPress={() => navigation.push('DBCategory', { category: parent_data.id })} icon="chevron-left" color={theme.page_content.fg} />
              <Image style={{ height: 32, width: 32, marginHorizontal: 8 }} source={getIcon(parent_data.custom_icon ?? parent_data.icon)} />
              <View style={{ flex: 1 }}>
                <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{parent_data.name}</Text>
                <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{t(`db:go_back`)}</Text>
              </View>
            </View> : <View style={{ padding: 4, flexDirection: "row", alignItems: "center" }}>
                <IconButton size={24} onPress={() => navigation.push('DBSearch')} icon="chevron-left" color={theme.page_content.fg} />
                {/* <Image style={{height:32,width:32,marginHorizontal:8}} source={{uri:parent_data.custom_icon??`https://munzee.global.ssl.fastly.net/images/pins/${encodeURIComponent(parent_data.icon)}.png`}} /> */}
                <View style={{ flex: 1 }}>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{t('screens:DBSearch')}</Text>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{t(`db:go_back`)}</Text>
                </View>
              </View>)}
            <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 24, color: theme.page_content.fg, padding: 4, textAlign: "center" }}>{category_data.name}</Text>
            {category_data?.seasonal && <>
              {/* <Text allowFontScaling={false} style={{...font("bold"),fontSize:20,color:theme.page_content.fg,textAlign:"center"}}>{category_data.id}</Text> */}
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{moment(category_data.seasonal.starts).format('L LT')} - {moment(category_data.seasonal.ends).format('L LT')}</Text>
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{t('bouncers:duration', { duration: moment.duration(moment(category_data.seasonal.starts).diff(moment(category_data.seasonal.ends))).humanize() })}</Text>
            </>}
            {[...types.filter(i => i.category === category), ...categories.filter(i => i.parents.includes(category))].filter(i => !i.hidden).map(i => <TouchableRipple key={i.id} onPress={i.category ? () => navigation.push('DBType', { munzee: i.icon }) : () => navigation.push('DBCategory', { category: i.id })}>
              <View style={{ padding: 8, flexDirection: "row", alignItems: "center" }}>
                <Image style={{ height: 32, width: 32, marginHorizontal: 4 }} source={getIcon(i.custom_icon ?? i.icon)} />
                <View style={{ flex: 1 }}>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{i.name}</Text>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{i.category ? `#${i.id}` : t(`db:category`)}</Text>
                </View>
                <MaterialCommunityIcons size={24} name="chevron-right" color={theme.page_content.fg} />
              </View>
            </TouchableRipple>)}
          </View>
        </Card>
      </View>
    </ScrollView>
  );
}
Example #18
Source File: index.js    From puente-reactnative-collect with MIT License 4 votes vote down vote up
NamePhoneEmail = () => {
  useEffect(() => {
    async function setUserInformation() {
      const currentUser = await getData('currentUser');
      setObjectId(currentUser.objectId);
      const fname = currentUser.firstname;
      const lname = currentUser.lastname;
      const phoneNumber = currentUser.phonenumber;
      const { email } = currentUser;

      setUserObject({
        firstName: fname,
        lastName: lname,
        phoneNumber,
        email
      });
    }
    setUserInformation().then(() => {
      setInputs([
        {
          label: I18n.t('namePhoneEmailSettings.userInformation.fname'),
          value: userObject.firstName,
          key: 'firstName'
        },
        {
          label: I18n.t('namePhoneEmailSettings.userInformation.lname'),
          value: userObject.lastName,
          key: 'lastName'
        },
        {
          label: I18n.t('namePhoneEmailSettings.userInformation.phoneNumber'),
          value: userObject.phoneNumber,
          key: 'phoneNumber'
        },
        {
          label: I18n.t('namePhoneEmailSettings.userInformation.email'),
          value: userObject.email,
          key: 'email'
        }
      ]);
      setUpdated(false);
    });
  }, [updated]);

  const [userObject, setUserObject] = useState({});
  const [edit, setEdit] = useState('');
  const [inputs, setInputs] = useState([]);
  const [objectId, setObjectId] = useState('');
  const [updated, setUpdated] = useState(false);
  const [submitting, setSubmitting] = useState(false);

  const updateUserObject = (key, text) => {
    const copyUserObject = userObject;
    copyUserObject[key] = text;
    setUserObject(copyUserObject);
  };

  const handleFailedAttempt = () => {
    Alert.alert(
      I18n.t('global.error'),
      I18n.t('namePhoneEmailSettings.errorMessage'), [
        { text: 'OK' }
      ],
      { cancelable: true }
    );
  };

  const handleSucccessfullAttempt = () => {
    Alert.alert(
      I18n.t('global.success'),
      I18n.t('namePhoneEmailSettings.successMessage'), [
        { text: 'OK' }
      ],
      { cancelable: true }
    );
  };

  const updateUser = async () => {
    setSubmitting(true);
    const postParams = {
      objectId,
      firstname: userObject.firstName,
      lastname: userObject.lastName,
      email: userObject.email,
      phonenumber: userObject.phoneNumber
    };
    const currentUser = await getData('currentUser');

    const user = await Parse.User.logIn(currentUser.username, currentUser.password);
    for (const key in postParams) { //eslint-disable-line
      user.set(String(key), postParams[key]);
    }

    const submitAction = () => {
      setTimeout(() => {
        setSubmitting(false);
        handleSucccessfullAttempt();
      }, 1000);
    };

    await user.save().then(async (updatedUser) => {
      await storeData(updatedUser, 'currentUser').then(() => {
        setUpdated(true);
        submitAction();
      }, (error) => {
        console.log(error); //eslint-disable-line
        setSubmitting(false);
        handleFailedAttempt();
      });
    }, (error) => {
      console.log(error); //eslint-disable-line
      setSubmitting(false);
      handleFailedAttempt();
    });
  };

  return (
    <View>
      <Headline>{I18n.t('namePhoneEmailSettings.namePhoneEmail')}</Headline>
      <View style={styles.horizontalLinePrimary} />
      {inputs.length > 0 && inputs.map((result) => (
        <View key={result.key}>
          <Text style={styles.text}>{result.label}</Text>
          <View>
            {edit !== result.key && (
              <View style={styles.textContainer}>
                <Text style={styles.text}>{userObject[result.key]}</Text>
                <Button
                  style={{ marginLeft: 'auto' }}
                  onPress={() => {
                    setEdit(result.key);
                  }}
                >
                  {I18n.t('findRecordSettings.edit')}
                </Button>
              </View>
            )}
            {edit === result.key && (
              <View style={styles.textContainer}>
                <TextInput
                  style={{ flex: 3 }}
                  placeholder={result.value}
                  mode="outlined"
                  onChangeText={(text) => updateUserObject(result.key, text)}
                />
                <View style={styles.buttonContainer}>
                  <IconButton
                    icon="check"
                    size={25}
                    color={theme.colors.primary}
                    style={styles.svg}
                    onPress={() => {
                      setEdit('');
                    }}
                  />
                  <IconButton
                    icon="window-close"
                    size={25}
                    color={theme.colors.primary}
                    style={styles.svg}
                    onPress={() => {
                      setEdit('');
                    }}
                  />
                </View>
              </View>
            )}
          </View>
          <View style={styles.horizontalLineGray} />

        </View>
      ))}
      {submitting ? (
        <ActivityIndicator
          size="large"
          color={theme.colors.primary}
        />
      ) : (
        <Button onPress={() => updateUser()}>{I18n.t('global.submit')}</Button>
      )}
    </View>
  );
}
Example #19
Source File: Search.js    From Legacy with Mozilla Public License 2.0 4 votes vote down vote up
export default function SearchScreen({ navigation }) {
  var {t} = useTranslation();
  var theme = useSelector(i=>i.themes[i.theme])
  var input = React.useRef();
  var [value,setValue] = React.useState('');
  var [search,setSearch] = React.useState('');
  var [selectedClanGroup,setSelectedClanGroup] = React.useState(null);
  var [timeoutC,setTimeoutC] = React.useState(null);
  function onValue(val) {
    if(timeoutC) clearTimeout(timeoutC)
    setValue(val);
    setTimeoutC(setTimeout(() => {
      return setSearch(val);
    }, 500))
  }
  var dispatch = useDispatch();
  var clanBookmarks = useSelector(i => i.clanBookmarks);
  function addClan(clan) {
    dispatch(clanBookmarksR(clanBookmarks.concat([clan])));
  }
  function removeClan(clan) {
    dispatch(clanBookmarksR(clanBookmarks.filter(i=>i.clan_id!=clan.clan_id)));
  }
  var clansInGroup = [];
  if(groups.find(i=>i.title==selectedClanGroup)) {
    clansInGroup = groups.find(i=>i.title==selectedClanGroup).clans;
  }
  
  var reqData = {
    endpoint: `clan/list/v1`,
    data: {
      query: search,
      format: "list"
    },
    cuppazee: true
  }
  var clans = useSelector(i => i.request_data[stringify(reqData)] ?? {})
  useFocusEffect(
    React.useCallback(() => {
      if(search.length>=3) dispatch(request.add(reqData))
      return () => {
        if(search.length>=3) dispatch(request.remove(reqData))
      };
    }, [search])
  );
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{padding:4,width:"100%"}}>
        <Card noPad cardStyle={{flexDirection: "row", backgroundColor: "#fff", alignItems:"stretch"}}>
          <TextInput
            onSubmitEditing={()=>setSearch(value)}
            ref={input}
            style={{ paddingHorizontal: 8, flex: 1, borderRadius: 8, borderBottomLeftRadius: 8, height: 40 }}
            onChangeText={onValue}
            value={value}
            returnKeyType="search"
          />
        </Card>
      </View>
      <View style={{padding:4}}>
        <Card noPad>
          <View>
            {!search&&<Text allowFontScaling={false} style={{textAlign:"center",...font("bold"),fontSize:16,color:theme.page_content.fg}}>{t('search:clan')}</Text>}
            {!!search&&!clans?.data&&<View style={{height:100,justifyContent:"center",alignItems:"center"}}>
              <ActivityIndicator size={32} color={theme.page_content.fg} />
            </View>}
            {(search?clans?.data?.slice?.(0,20):clansInGroup)?.map?.(i=><View key={i.clan_id} style={{padding: 4, flexDirection: "row", alignItems: "center"}}>
              {!clanBookmarks.find(x=>x.clan_id==i.clan_id)&&<IconButton size={24} onPress={()=>addClan(i)} icon="bookmark-plus" color="#016930" />}
              {!!clanBookmarks.find(x=>x.clan_id==i.clan_id)&&<IconButton size={24} onPress={()=>removeClan(i)} icon="bookmark-minus" color="#ff2222" />}
              <Image style={{height:24,width:24,marginRight:8,marginLeft:-8,borderRadius:12}} source={{uri:i.logo??`https://munzee.global.ssl.fastly.net/images/clan_logos/${Number(i.clan_id).toString(36)}.png`}} />
              <View style={{flex:1}}>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:16,color:theme.page_content.fg}}>{i.name}</Text>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:12,color:theme.page_content.fg}}>{i.tagline}</Text>
              </View>
              <IconButton size={24} onPress={()=>navigation.navigate('Clan',{clanid:i.clan_id})} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
            {!search&&groups.map(i=><View key={i.clan_id} style={{padding: 4, flexDirection: "row", alignItems: "center"}}>
              <Image style={{height:32,width:32,marginHorizontal:8,borderRadius:8}} source={{uri:i.icon??`https://munzee.global.ssl.fastly.net/images/clan_logos/${Number(i.clan_id).toString(36)}.png`}} />
              <View style={{flex:1}}>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:16,color:theme.page_content.fg}}>{i.title}</Text>
              </View>
              <IconButton size={24} onPress={()=>setSelectedClanGroup(i.title)} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
          </View>
        </Card>
      </View>
    </ScrollView>
  );
}
Example #20
Source File: Auth.js    From Legacy with Mozilla Public License 2.0 4 votes vote down vote up
export default function AuthScreen () {
  var {t} = useTranslation();
  var dispatch = useDispatch();
  var theme = useSelector(i=>i.themes[i.theme]);
  var hasLogin = useSelector(i=>Object.keys(i.logins).length>0);
  var userBookmarks = useSelector(i => i.userBookmarks);
  function addUser(user) {
    if(!userBookmarks.find(i=>i.user_id==user.user_id)) dispatch(userBookmarksR(userBookmarks.concat([user])));
  }
  var [loading,setLoading] = React.useState(false);
  var [redirect,setRedirect] = React.useState(false);
  var [now, setNow] = React.useState(Date.now());
  React.useEffect(()=>{
    var x = setInterval(()=>{
      setNow(Date.now());
    },1000);
    return ()=>clearInterval(x);
  })
  const navigation = useNavigation();
  const discovery = {
    authorizationEndpoint: 'https://api.munzee.com/oauth',
    tokenEndpoint: 'https://api.munzee.com/oauth/login',
  };

  const [request, response, promptAsync] = AuthSession.useAuthRequest(
    {
      clientId: config.client_id,
      scopes: ['read'],
      redirectUri: config.redirect_uri,
      state: JSON.stringify({
        redirect: Oconfig.redirect_uri,
        platform: Platform.OS
      })
    },
    discovery
  );

  React.useEffect(() => {
    if (response) {
      (async function() {
        if(!response.params || !response.params.teaken) return setLoading(false);
        var x = {};
        x[response.params.user_id] = {
          username: response.params.username,
          teaken: response.params.teaken
        }
        var y = await fetch(`https://server.cuppazee.app/auth/get/v2?teaken=${encodeURIComponent(response.params.teaken)}&user_id=${encodeURIComponent(response.params.user_id)}&from=${encodeURIComponent(FROM)}`)
        x[response.params.user_id].token = (await y.json()).data;
        dispatch(login(x));
        addUser({
          user_id: response.params.user_id,
          username: response.params.username
        });
        setLoading(false);
        setRedirect(response.params.username);
      })()
    }
  }, [response]);
  if(redirect) setTimeout(()=>navigation.replace('UserDetails',{username:redirect}),500)
  return <View style={{flex:1,justifyContent:"center",alignItems:"center",backgroundColor:theme.page_content.bg}}>{
    loading ? <View style={{flex:1,justifyContent:"center",alignItems:"center"}}><ActivityIndicator size="large" color={theme.page_content.fg} /></View> : <>
      <View style={{flex:1,justifyContent:"center",alignItems:"center"}}>
      <Text allowFontScaling={false} style={{color:theme.page_content.fg,fontSize:24}}>{hasLogin?t('auth:add'):t('auth:welcome')}</Text>
        <Text allowFontScaling={false} style={{color:theme.page_content.fg,fontSize:16}}>{t('auth:tap')}</Text>
        <IconButton
          size={32}
          onPress={() => {
            setLoading(true);
            promptAsync({
              useProxy: Oconfig.useProxy,
              redirectUri: config.redirect_uri
            });
          }}
          color={theme.page_content.fg}
          icon="login-variant"
        />
      </View>
      {/* {now >= 1594314000000 && <Button icon="flag" mode="contained" style={{backgroundColor:theme.navigation.bg,marginBottom:8}} onPress={()=>navigation.navigate('AllCampLeaderboard')}>Camps Leaderboard</Button>} */}
    </>
  }</View>
}
Example #21
Source File: RequestTokenForm.js    From mern-stack with MIT License 4 votes vote down vote up
render() {
    const {
      clearErrorMessage,
      errorMessage,
      isProcessing,
      navigation,
      title,
      theme: { colors },
    } = this.props;
    return (
      <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : null}
        style={styles.container}
      >
        <ScrollView
          keyboardShouldPersistTaps="handled"
          keyboardDismissMode="on-drag"
        >
          <IconButton
            icon="chevron-left"
            color={colors.primary}
            size={30}
            accessibilityLabel="Back to sign in"
            onPress={() => navigation.goBack()}
          />
          <Logo />
          <Spacer>
            <Title style={{ alignSelf: 'center', color: colors.primary }}>
              {title}
            </Title>
          </Spacer>
          <Spacer>
            <TextInput
              label="Email"
              mode="outlined"
              dense
              value={this.state.email}
              autoCapitalize="none"
              autoCorrect={false}
              keyboardType="email-address"
              onChangeText={(email) => this.setState({ email })}
              onSubmitEditing={this.onSubmit}
              onFocus={clearErrorMessage}
              disabled={isProcessing || !!this.state.message}
            />
          </Spacer>
          <Spacer vertical={16}>
            <Button
              mode="contained"
              accessibilityLabel="Submit"
              onPress={this.onSubmit}
              loading={isProcessing}
              disabled={isProcessing || !!this.state.message}
            >
              Submit
            </Button>
          </Spacer>
        </ScrollView>
        <Snackbar
          visible={errorMessage}
          onDismiss={clearErrorMessage}
          action={{
            label: 'Dismiss',
            accessibilityLabel: 'Dismiss',
            onPress: () => {},
          }}
        >
          {errorMessage}
        </Snackbar>
        <Snackbar
          visible={this.state.message}
          onDismiss={() => navigation.goBack()}
          action={{
            label: 'Go Back',
            accessibilityLabel: 'Go Back',
            onPress: () => {},
          }}
        >
          {this.state.message}
        </Snackbar>
      </KeyboardAvoidingView>
    );
  }
Example #22
Source File: RecordItem.js    From react-native-nfc-rewriter with MIT License 4 votes vote down vote up
function RecordItem(props) {
  const {record, removeIdx, goToHandler, onCopy, idx} = props;
  return (
    <List.Item
      title={record.name}
      right={() => (
        <View
          style={{
            flexDirection: 'row',
            alignItems: 'center',
            alignSelf: 'center',
          }}>
          <IconButton
            icon={() => (
              <Icon name="delete" size={22} style={{alignSelf: 'center'}} />
            )}
            onPress={() => removeIdx(idx)}
          />

          <IconButton
            icon={() => (
              <Image
                source={require('../../../images/save_as.png')}
                style={{width: 24, height: 24}}
                resizeMode="contain"
              />
            )}
            onPress={() => onCopy()}
          />

          <IconButton
            icon={() => (
              <Icon name="share" size={22} style={{alignSelf: 'center'}} />
            )}
            onPress={() => {
              Share.share({
                title: 'My NFC Record',
                url: `com.revteltech.nfcopenrewriter://share?data=${JSON.stringify(
                  record,
                )}`,
              });
            }}
          />

          <IconButton
            icon={() => (
              <Icon
                name="arrow-forward"
                size={22}
                style={{alignSelf: 'center'}}
              />
            )}
            onPress={() => goToHandler(record)}
          />
        </View>
      )}
    />
  );
}
Example #23
Source File: index.js    From react-native-nfc-rewriter with MIT License 4 votes vote down vote up
function HomeScreen(props) {
  const {navigation} = props;
  const [supported, setSupported] = React.useState(null);
  const [enabled, setEnabled] = React.useState(null);
  const padding = 40;
  const width = Dimensions.get('window').width - 2 * padding;

  React.useEffect(() => {
    async function initNfc() {
      try {
        const success = await NfcProxy.init();
        setSupported(success);
        setEnabled(await NfcProxy.isEnabled());

        if (success) {
          function onBackgroundTag(bgTag) {
            navigation.navigate('TagDetail', {tag: bgTag});
          }

          function onDeepLink(url, launch) {
            try {
              const customScheme = [
                'com.washow.nfcopenrewriter://', // android
                'com.revteltech.nfcopenrewriter://', // ios
              ].find((scheme) => {
                return scheme === url.slice(0, scheme.length);
              });

              if (!customScheme) {
                return;
              }

              url = url.slice(customScheme.length);

              // issue #23: we might have '?' in our payload, so we cannot simply "split" it
              let action = url;
              let query = '';
              let splitIdx = url.indexOf('?');

              if (splitIdx > -1) {
                action = url.slice(0, splitIdx);
                query = url.slice(splitIdx);
              }

              const params = qs.parse(query);
              if (action === 'share') {
                const sharedRecord = JSON.parse(params.data);
                if (sharedRecord.payload?.tech === NfcTech.Ndef) {
                  navigation.navigate('NdefWrite', {savedRecord: sharedRecord});
                } else if (sharedRecord.payload?.tech === NfcTech.NfcA) {
                  navigation.navigate('CustomTransceive', {
                    savedRecord: sharedRecord,
                  });
                } else if (sharedRecord.payload?.tech === NfcTech.IsoDep) {
                  navigation.navigate('CustomTransceive', {
                    savedRecord: sharedRecord,
                  });
                } else {
                  console.warn('unrecognized share payload tech');
                }
              }
            } catch (ex) {
              console.warn('fail to parse deep link', ex);
            }
          }

          // get the initial launching tag
          const bgTag = await NfcManager.getBackgroundTag();
          if (bgTag) {
            onBackgroundTag(bgTag);
          } else {
            const link = await Linking.getInitialURL();
            console.warn('DEEP LINK', link);
            if (link) {
              onDeepLink(link, true);
            }
          }

          // listen to other background tags after the app launched
          NfcManager.setEventListener(
            NfcEvents.DiscoverBackgroundTag,
            onBackgroundTag,
          );

          // listen to the NFC on/off state on Android device
          if (Platform.OS === 'android') {
            NfcManager.setEventListener(
              NfcEvents.StateChanged,
              ({state} = {}) => {
                NfcManager.cancelTechnologyRequest().catch(() => 0);
                if (state === 'off') {
                  setEnabled(false);
                } else if (state === 'on') {
                  setEnabled(true);
                }
              },
            );
          }

          Linking.addEventListener('url', (event) => {
            if (event.url) {
              onDeepLink(event.url, false);
            }
          });
        }
      } catch (ex) {
        console.warn(ex);
        Alert.alert('ERROR', 'fail to init NFC', [{text: 'OK'}]);
      }
    }

    initNfc();
  }, [navigation]);

  function renderNfcButtons() {
    return (
      <View
        style={{
          flex: 2,
          alignItems: 'stretch',
          alignSelf: 'center',
          width,
        }}>
        <Button
          mode="contained"
          onPress={async () => {
            const tag = await NfcProxy.readTag();
            if (tag) {
              navigation.navigate('TagDetail', {tag});
            }
          }}
          style={{marginBottom: 10}}>
          READ TAGs
        </Button>

        <Button
          mode="contained"
          onPress={async () => {
            navigation.navigate('NdefTypeList');
          }}
          style={{marginBottom: 10}}>
          WRITE NDEF
        </Button>

        <Button
          mode="contained"
          onPress={async () => {
            navigation.navigate('ToolKit');
          }}
          style={{marginBottom: 10}}>
          Tool Kit
        </Button>

        <Button
          mode="contained"
          onPress={async () => {
            navigation.navigate('TagKit');
          }}
          style={{marginBottom: 10}}>
          Tag Kit
        </Button>

        <Button
          mode="outlined"
          onPress={async () => {
            navigation.navigate('SavedRecord');
          }}>
          MY RECORDS
        </Button>
      </View>
    );
  }

  function renderNfcNotEnabled() {
    return (
      <View
        style={{
          flex: 2,
          alignItems: 'stretch',
          alignSelf: 'center',
          width,
        }}>
        <Text style={{textAlign: 'center', marginBottom: 10}}>
          Your NFC is not enabled. Please first enable it and hit CHECK AGAIN
          button
        </Text>

        <Button
          mode="contained"
          onPress={() => NfcProxy.goToNfcSetting()}
          style={{marginBottom: 10}}>
          GO TO NFC SETTINGS
        </Button>

        <Button
          mode="outlined"
          onPress={async () => {
            setEnabled(await NfcProxy.isEnabled());
          }}>
          CHECK AGAIN
        </Button>
      </View>
    );
  }

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView />
      <View style={{flex: 1, padding}}>
        <View
          style={{
            flex: 3,
            justifyContent: 'center',
            alignItems: 'center',
          }}>
          <Image
            source={require('../../../images/nfc-rewriter-icon.png')}
            style={{width: 250, height: 250}}
            resizeMode="contain"
          />
        </View>

        {supported && !enabled && renderNfcNotEnabled()}

        {supported && enabled && renderNfcButtons()}

        <IconButton
          icon={() => <Icon name="settings" size={32} />}
          style={styles.settingIcon}
          onPress={() => {
            navigation.navigate('Settings');
          }}
        />
      </View>
    </>
  );
}
Example #24
Source File: Drawer.js    From Legacy with Mozilla Public License 2.0 4 votes vote down vote up
export default function CustomDrawerContent(props) {
  var [helpOpen, setHelpOpen] = React.useState(false);
  var [donateOpen, setDonateOpen] = React.useState(false);
  var [paypalOpen, setPaypalOpen] = React.useState(false);
  var mini = props.mini;
  var { t } = useTranslation();
  var theme = useSelector(i => i.themes[i.theme]);
  var clanBookmarks = useSelector(i => i.clanBookmarks);
  var userBookmarks = useSelector(i => i.userBookmarks);
  // const { data: zeecretTeams } = useZeecretTeam(null, true);
  var route = useSelector(i => i.route);
  var nav = props.navigation;
  var [showMoreClan, setShowMoreClan] = React.useState(false);
  var [showMoreUser, setShowMoreUser] = React.useState(false);
  var [now, setNow] = React.useState(Date.now());
  React.useEffect(() => {
    var x = setInterval(() => {
      setNow(Date.now());
    }, 1000);
    return () => clearInterval(x);
  })
  var top = [
    // { title: "Camps Leaderboard", icon: "flag", page: "AllCampWeeks" },
  ].filter(i => !i.hide)
  var pages = [
    // { title: t(`common:maps`), icon: "map", page: "Map" },
    { title: t(`common:bouncers`), icon: "map-marker", page: "Bouncers" },
    { title: t(`common:munzee_types`), icon: "database", page: "DBSearch" },
    { title: t(`common:calendar`), icon: "calendar", page: "Calendar" },
    { title: t(`common:evo_planner`), icon: "dna", page: "EvoPlanner" },
    // { title: t(`common:scanner`), icon: "qrcode", page: "Scanner", hide: Platform.OS === "web" },
    { title: t(`common:weekly_challenge`), icon: "calendar", page: "WeeklyWeeks" },
    { title: "Zeecret Agents Competition", icon: "briefcase", page: "CompetitionHome" },
    { title: "Bookmark Manager", icon:"bookmark", page:"Bookmarks" },
  ].filter(i => !i.hide)
  var more = [
    { title: t(`common:notifications`), icon: "bell", page: "Notifications", hide: Platform.OS === "web" },
    { title: t(`common:settings`), icon: "settings", page: "Settings" },
    { title: t(`common:app_info`), icon: "information", page: "Info" },
    { title: `GitHub`, icon: "github-circle", page: "https://github.com/CuppaZee/CuppaZee", link: true }
  ].filter(i => !i.hide)
  var itemProps = {
    side: props.side,
    mini: mini,
    activeBackgroundColor: theme.navigation_selected?.bg ?? theme.navigation.fg,
    activeTintColor: theme.navigation_selected?.fg ?? theme.navigation.bg,
    inactiveTintColor: theme.navigation.fg
  }
  return (
    <DrawerContentScrollView style={{ backgroundColor: theme.navigation.bg, ...(theme.page_content.border ? { borderRightWidth: 1, borderRightColor: "white" } : {}) }} {...props}>
      {/* <View style={{ paddingTop: 8, paddingBottom: 4, paddingLeft: 16 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>Remember this is a{Platform.OS == "android" ? 'n Early Access' : ' Beta'} build</Text>
        <Text allowFontScaling={false} style={{ fontSize: 12, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>Feedback is welcome via Messenger or Email</Text>
      </View> */}
      {Platform.OS == "web" && globalThis?.navigator?.userAgent?.match?.(/Android/) && <View style={{ paddingTop: 8, paddingBottom: 4, paddingLeft: 8 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>The CuppaZee App is now on Google Play</Text>
        <Text allowFontScaling={false} style={{ fontSize: 12, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>Download it now!</Text>
      </View>}
      {Platform.OS == "web" && globalThis?.navigator?.userAgent?.match?.(/iPhone|iPad|iPod/) && <View style={{ paddingTop: 8, paddingBottom: 4, paddingLeft: 8 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>The CuppaZee App is now on the App Store</Text>
        <Text allowFontScaling={false} style={{ fontSize: 12, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>Download it now!</Text>
      </View>}
      {top.map?.(i => <DrawerItem
        key={i.title}
        {...itemProps}
        style={{ marginVertical: 0, opacity: i.disabled ? 0.6 : 1 }}
        focused={route.name == i.page}
        icon={({ focused, color, size }) => <MaterialCommunityIcons name={i.icon} color={color} size={24} style={{ margin: 4 }} />}
        label={i.title}
        onPress={i.disabled ? null : (i.link ? () => Linking.openURL(i.page) : () => nav.reset({
          index: 1,
          routes: [
            { name: '__primary', params: { screen: i.page } },
          ],
        }))
        }
      />)}
      <View style={{ paddingLeft: 8 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>{t(`common:users`)}</Text>
      </View>
      <View style={{ paddingHorizontal: 4, flexDirection: "row", justifyContent: "space-between" }}>
        <IconButton
          style={{
            backgroundColor: route.name == "AllUsers" ? itemProps.activeBackgroundColor : null
          }}
          icon="format-list-bulleted"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "AllUsers" } },
            ],
          })}
        />
        <IconButton
          style={{
            backgroundColor: route.name == "UserSearch" ? itemProps.activeBackgroundColor : null
          }}
          icon="magnify"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "UserSearch" } },
            ],
          })}
        />
        <IconButton
          disabled={true}
          style={{
            backgroundColor: route.name == "UserRankings" ? itemProps.activeBackgroundColor : null
          }}
          icon="trophy-outline"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "UserRankings" } },
            ],
          })}
        />
        {/* <IconButton
          disabled={true}
          style={{
            backgroundColor: route.name == "UserBookmarks" ? itemProps.activeBackgroundColor : null
          }}
          icon="bookmark-outline"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "UserBookmarks" } },
            ],
          })
          }
        /> */}
      </View>
      {userBookmarks?.slice?.(0, showMoreUser ? Infinity : userBookmarks.length > 6 ? 5 : 6)?.filter?.(i => i)?.map?.(i => <DrawerItem
        key={`user_${i.user_id}`}
        {...itemProps}
        style={{ marginVertical: 0 }}
        focused={route.name?.startsWith?.('User') && route.params?.username == i.username}
        icon={({ focused, color, size }) => <Image style={{ height: 32, width: 32, borderRadius: 16 }} source={{ uri: i.logo ?? `https://munzee.global.ssl.fastly.net/images/avatars/ua${Number(i.user_id || 0).toString(36)}.png` }} />}
        label={i.username}
        onPress={() => nav.reset({
          index: 1,
          routes: [
            { name: '__primary', params: { screen: "UserDetails", params: { username: i.username } } },
          ],
        })
        }
        // right={zeecretTeams?.[i.username] ? ({ focused, color, size }) => <MaterialCommunityIcons name={zeecretTeams[i.username].startsWith("pine") ? "pine-tree" : "bomb"} color={zeecretTeams[i.username].endsWith('_false') ? "#ff0000" : color} size={24} style={{ margin: 4 }} /> : null}
      />)}
      {userBookmarks.length > 6 && <DrawerItem
        {...itemProps}
        style={{ marginVertical: 0 }}
        focused={false}
        icon={({ focused, color, size }) => <MaterialCommunityIcons name={showMoreUser ? "chevron-up" : "chevron-down"} color={color} size={24} style={{ margin: 4 }} />}
        label={showMoreUser ? t(`common:show_less`) : t(`common:show_more`)}
        onPress={() => setShowMoreUser(!showMoreUser)}
      />}
      {/* <DrawerItem
        {...itemProps}
        style={{ marginVertical: 0 }}
        focused={route.name == "UserSearch"}
        icon={({ focused, color, size }) => <MaterialCommunityIcons name="magnify" color={color} size={24} style={{ margin: 4 }} />}
        label={t(`common:find_user`)}
        onPress={() => nav.reset({
          index: 1,
          routes: [
            { name: '__primary', params: { screen: "UserSearch" } },
          ],
        })
        }
      /> */}
      <Divider theme={{ dark: theme.id !== "white" }} />
      <View style={{ paddingTop: 8, paddingLeft: 8 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>{t('common:clan', { count: 2 })}</Text>
      </View>
      <View style={{ paddingHorizontal: 4, flexDirection: "row", justifyContent: "space-between" }}>
        <IconButton
          style={{
            backgroundColor: route.name == "AllClans" ? itemProps.activeBackgroundColor : null
          }}
          icon="format-list-bulleted"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "AllClans" } },
            ],
          })}
        />
        <IconButton
          style={{
            backgroundColor: route.name == "ClanSearch" ? itemProps.activeBackgroundColor : null
          }}
          icon="magnify"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "ClanSearch" } },
            ],
          })}
        />
        {/* <IconButton
          disabled={true}
          style={{
            backgroundColor: route.name == "ClanRequirements" && route.params.gameid < 87 ? itemProps.activeBackgroundColor : null
          }}
          icon="history"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "ClanRequirements", params: { gameid: 87 } } },
            ],
          })
          }
        /> */}
        <IconButton
          style={{
            backgroundColor: route.name == "ClanRequirements" && route.params.year == 2020 && route.params.month == 11 ? itemProps.activeBackgroundColor : null
          }}
          icon="playlist-check"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "ClanRequirements", params: { year: 2020, month: 11 } } },
            ],
          })
          }
        />
        <IconButton
          style={{
            backgroundColor: route.name == "ClanRequirements" && route.params.year == 2020 && route.params.month == 12 ? itemProps.activeBackgroundColor : null,
            borderWidth: 1,
            borderColor: theme.navigation.fg
          }}
          icon="star"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "ClanRequirements", params: { year: 2020, month: 12 } } },
            ],
          })
          }
        />
        {/* <IconButton
          style={{
            backgroundColor: route.name == "ClanRequirements" && route.params.gameid == 89 ? itemProps.activeBackgroundColor : null
          }}
          icon="new-box"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "ClanRequirements", params: { gameid: 89 } } },
            ],
          })
          }
        /> */}
        {/* <IconButton
          disabled={true}
          style={{
            backgroundColor: route.name == "ClanBookmarks" ? itemProps.activeBackgroundColor : null
          }}
          icon="bookmark-outline"
          color={itemProps.inactiveTintColor}
          onPress={() => nav.reset({
            index: 1,
            routes: [
              { name: '__primary', params: { screen: "ClanBookmarks" } },
            ],
          })
          }
        /> */}
      </View>
      {clanBookmarks?.slice?.(0, showMoreClan ? Infinity : clanBookmarks.length > 6 ? 5 : 6)?.filter?.(i => i)?.map?.(i => <DrawerItem
        key={`clan_${i.clan_id}`}
        {...itemProps}
        style={{ marginVertical: 0 }}
        focused={route.name == "Clan" && route.params?.clanid == Number(i.clan_id)}
        icon={({ focused, color, size }) => <Image style={{ height: 32, width: 32, borderRadius: 16 }} source={{ uri: i.logo ?? `https://munzee.global.ssl.fastly.net/images/clan_logos/${(i.clan_id || 0).toString(36)}.png` }} />}
        label={i.name}
        onPress={() => nav.reset({
          index: 1,
          routes: [
            { name: '__primary', params: { screen: "Clan", params: { clanid: Number(i.clan_id) } } },
          ],
        })
        }
      />)}
      {clanBookmarks.length > 6 && <DrawerItem
        {...itemProps}
        style={{ marginVertical: 0 }}
        focused={false}
        icon={({ focused, color, size }) => <MaterialCommunityIcons name={showMoreClan ? "chevron-up" : "chevron-down"} color={color} size={24} style={{ margin: 4 }} />}
        label={showMoreClan ? t(`common:show_less`) : t(`common:show_more`)}
        onPress={() => setShowMoreClan(!showMoreClan)}
      />}
      <Divider theme={{ dark: theme.id !== "white" }} />
      <View style={{ paddingTop: 8, paddingBottom: 4, paddingLeft: 8 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>{t('common:tools')}</Text>
      </View>
      {pages.map?.(i => <DrawerItem
        key={i.title}
        {...itemProps}
        style={{ marginVertical: 0 }}
        focused={route.name == i.page}
        icon={({ focused, color, size }) => <MaterialCommunityIcons name={i.icon} color={color} size={24} style={{ margin: 4 }} />}
        label={i.title}
        onPress={() => nav.reset({
          index: 1,
          routes: [
            { name: '__primary', params: { screen: i.page } },
          ],
        })
        }
      />)}
      <Divider theme={{ dark: theme.id !== "white" }} />
      <View style={{ paddingTop: 8, paddingBottom: 4, paddingLeft: 8 }}>
        <Text allowFontScaling={false} style={{ fontSize: 16, ...font("bold"), color: theme.navigation.fg, opacity: 0.8 }}>{t('common:more')}</Text>
      </View>
      {more.map?.(i => <DrawerItem
        key={i.title}
        {...itemProps}
        style={{ marginVertical: 0, opacity: i.disabled ? 0.6 : 1 }}
        focused={route.name == i.page}
        icon={({ focused, color, size }) => <MaterialCommunityIcons name={i.icon} color={color} size={24} style={{ margin: 4 }} />}
        label={i.title}
        onPress={i.disabled ? null : (i.link ? () => Linking.openURL(i.page) : () => nav.reset({
          index: 1,
          routes: [
            { name: '__primary', params: { screen: i.page } },
          ],
        }))
        }
      />)}
      <Menu
        visible={donateOpen}
        onDismiss={() => setDonateOpen(false)}
        anchor={
          <DrawerItem
            {...itemProps}
            style={{ marginVertical: 0 }}
            icon={({ focused, color, size }) => <MaterialCommunityIcons name="coin" color={color} size={24} style={{ margin: 4 }} />}
            label={t('common:donate')}
            onPress={() => setDonateOpen(true)}
          />
        }
        contentStyle={{ backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border }}
      >
        <View style={{ paddingHorizontal: 4, alignItems: "stretch" }}>
          <Button style={{ marginHorizontal: 4 }} color="#F96854" mode="contained" onPress={() => Linking.openURL('https://patreon.com/CuppaZee')} icon="patreon">{t('app_info:patreon_donate')}</Button>
          <Button style={{ marginHorizontal: 4, marginTop: 4 }} color="#29abe0" mode="contained" onPress={() => Linking.openURL('https://ko-fi.com/sohcah')} icon="coffee">{t('app_info:kofi_donate')}</Button>
          <Menu
            visible={paypalOpen}
            onDismiss={() => setPaypalOpen(false)}
            anchor={
              <Button style={{ marginHorizontal: 4, marginTop: 4 }} color="#009CDE" mode="contained" onPress={() => setPaypalOpen(true)} icon="paypal">{t('app_info:paypal_donate')}</Button>
            }
          >
            <View style={{ paddingHorizontal: 8 }}>
              <Text>{t('app_info:paypal_donate_desc')}</Text>
            </View>
          </Menu>
        </View>
      </Menu>
      <Menu
        visible={helpOpen}
        onDismiss={() => setHelpOpen(false)}
        anchor={
          <DrawerItem
            {...itemProps}
            style={{ marginVertical: 0 }}
            icon={({ focused, color, size }) => <MaterialCommunityIcons name="help-circle" color={color} size={24} style={{ margin: 4 }} />}
            label={t('common:help')}
            onPress={() => setHelpOpen(true)}
          />
        }
        contentStyle={{ backgroundColor: theme.page_content.bg, borderWidth: theme.page_content.border ? 1 : 0, borderColor: theme.page_content.border }}
      >
        <View style={{ paddingHorizontal: 4, alignItems: "center" }}>
          <View style={{ flexDirection: "row" }}>
            <Text allowFontScaling={false} style={{ color: theme.page_content.fg, fontSize: 16, ...font("bold") }}>{t('common:contact.facebook')} </Text>
            <TouchableRipple onPress={() => Linking.openURL('https://m.me/CuppaZee')}><Text allowFontScaling={false} style={{ color: theme.page_content.fg == "#000000" ? 'blue' : 'lightblue', fontSize: 16, ...font("bold") }}>@CuppaZee</Text></TouchableRipple>
          </View>
          <Text allowFontScaling={false} style={{ color: theme.page_content.fg, fontSize: 16 }}>{t('common:contact.email')}</Text>
        </View>
      </Menu>
    </DrawerContentScrollView>
  );
}
Example #25
Source File: index.js    From puente-reactnative-collect with MIT License 4 votes vote down vote up
SupportHome = ({
  logOut, settingsView, setSettingsView, setSettings
}) => {
  const [supportView, setSupportView] = useState('');

  const rateApp = async () => {
    if (await StoreReview.isAvailableAsync()) {
      StoreReview.requestReview();
    }
  };
  const inputs = [
    {
      key: 'feedback',
      label: I18n.t('supportHome.feedback'),
      button: true,
      touchable: false,
      action: null
    },
    {
      key: 'rateApp',
      label: I18n.t('supportHome.rateApp'),
      button: false,
      touchable: true,
      action: rateApp
    }
  ];
  return (
    <View>
      {settingsView === 'Support' && supportView === '' && (
        <View>
          <View style={{ flexDirection: 'row', marginLeft: 'auto', marginRight: 'auto' }}>
            <View style={{ paddingRight: '5%' }}>
              <Button onPress={() => setSettingsView('Settings')}>{I18n.t('accountSettings.settings')}</Button>
            </View>
            <View style={{ paddingLeft: '5%' }}>
              <Button mode="contained">
                {I18n.t('accountSettings.support')}
              </Button>
            </View>
          </View>
          <View style={{ paddingLeft: '5%', paddingRight: '5%', paddingTop: 20 }}>
            <Headline style={{ fontWeight: 'bold' }}>{I18n.t('supportHome.helpCenter')}</Headline>
            <View style={styles.horizontalLineGray} />
            {inputs.length > 0 && inputs.map((input) => (
              <View key={input.key}>
                {input.touchable ? (
                  <TouchableOpacity style={{ flexDirection: 'row' }} onPress={() => input.action()}>
                    <Text style={styles.text}>{input.label}</Text>
                    {input.button && (
                      <IconButton
                        icon="chevron-right"
                        size={30}
                        color={theme.colors.primary}
                        style={{ marginLeft: 'auto', marginTop: -5, marginBottom: -10 }}
                        onPress={() => {
                          setSupportView(input.key);
                        }}
                      />
                    )}
                  </TouchableOpacity>
                ) : (
                  <View style={{ flexDirection: 'row' }}>
                    <Text style={styles.text}>{input.label}</Text>
                    {input.button && (
                      <IconButton
                        icon="chevron-right"
                        size={30}
                        color={theme.colors.primary}
                        style={{ marginLeft: 'auto', marginTop: -5, marginBottom: -10 }}
                        onPress={() => {
                          setSupportView(input.key);
                        }}
                      />
                    )}
                  </View>
                )}
                <View style={styles.horizontalLineGray} />
              </View>
            ))}
          </View>
          <Button onPress={() => {
            setSettings(false);
          }}
          >
            {I18n.t('accountSettings.back')}
          </Button>
          <Button mode="contained" onPress={logOut} style={{ marginTop: 20, marginLeft: '5%', marginRight: '5%' }}>{I18n.t('accountSettings.logout')}</Button>
        </View>
      )}
      {supportView !== '' && (
        <View>
          <SupportSettings
            supportView={supportView}
            setSupportView={setSupportView}
          />
        </View>
      )}
    </View>
  );
}
Example #26
Source File: index.js    From puente-reactnative-collect with MIT License 4 votes vote down vote up
SettingsHome = ({
  logOut, settingsView, setSettingsView, setSettings,
  surveyingOrganization, scrollViewScroll, setScrollViewScroll
}) => {
  const [accountSettingsView, setAccountSettingsView] = useState('');
  const inputs = [
    {
      key: 'NamePhoneEmail',
      label: I18n.t('accountSettings.namePhoneEmail')
    },
    {
      key: 'ChangePassword',
      label: I18n.t('accountSettings.changePassword')
    },
    {
      key: 'FindRecords',
      label: I18n.t('accountSettings.findRecords')
    },
    {
      key: 'Language',
      label: I18n.t('accountSettings.language')
    },
    {
      key: 'OfflineData',
      label: I18n.t('accountSettings.offlineData')
    }
  ];

  return (
    <View>
      {settingsView === 'Settings' && accountSettingsView === '' && (
        <View>
          <View style={{ flexDirection: 'row', marginLeft: 'auto', marginRight: 'auto' }}>
            <View style={{ paddingRight: '5%' }}>
              <Button mode="contained">{I18n.t('accountSettings.settings')}</Button>
            </View>
            <View style={{ paddingLeft: '5%' }}>
              <Button onPress={() => setSettingsView('Support')}>
                {I18n.t('accountSettings.support')}
              </Button>
            </View>
          </View>
          <View style={{ paddingLeft: '5%', paddingRight: '5%', paddingTop: 20 }}>
            <Headline style={{ fontWeight: 'bold' }}>{I18n.t('accountSettings.accountSettings')}</Headline>
            <View style={styles.horizontalLineGray} />
            {inputs.length && inputs.map((input) => (
              <View key={input.key}>
                <View style={{ flexDirection: 'row' }}>
                  <Text style={styles.text}>{input.label}</Text>
                  <IconButton
                    icon="chevron-right"
                    size={30}
                    color={theme.colors.primary}
                    style={{ marginLeft: 'auto', marginTop: -5, marginBottom: -10 }}
                    onPress={() => {
                      setAccountSettingsView(input.key);
                    }}
                  />
                </View>
                <View style={styles.horizontalLineGray} />
              </View>
            ))}
          </View>
          <Button onPress={() => {
            setSettings(false);
          }}
          >
            {I18n.t('accountSettings.back')}
          </Button>
          <Button mode="contained" onPress={logOut} style={{ marginTop: 20, marginLeft: '5%', marginRight: '5%' }}>{I18n.t('accountSettings.logout')}</Button>
        </View>
      )}
      {accountSettingsView !== '' && (
        <View>
          <AccountSettings
            accountSettingsView={accountSettingsView}
            setAccountSettingsView={setAccountSettingsView}
            surveyingOrganization={surveyingOrganization}
            scrollViewScroll={scrollViewScroll}
            setScrollViewScroll={setScrollViewScroll}
          />
        </View>
      )}
    </View>
  );
}
Example #27
Source File: CapturesCategory.js    From Legacy with Mozilla Public License 2.0 4 votes vote down vote up
export default function SearchScreen({ navigation, route }) {
  var {t} = useTranslation();
  var moment = useMoment();
  var category = route.params.category;
  var theme = useSelector(i => i.themes[i.theme])
  var category_data = categories.find(i => i.id == category);
  var parent_datas = categories.filter(i => category_data.parents.includes(i.id));
  var username = route.params.username;
  function hasChild(cat) {
    return !!categories.find(i => i.parents.includes(cat.id));
  }
  const user_id = useAPIRequest({
    endpoint: 'user',
    data: { username },
    function: i=>i?.user_id
  })
  var data = useAPIRequest(user_id?{
    endpoint: 'user/specials',
    data: {user_id}
  }:null)
  var data_improved = (data??[]).map(i=>({
    logo: i.logo,
    name: i.name,
    count: Number(i.count),
    x: getType(i.logo,1)
  }))
  function get(x) {
    return data_improved.find(i=>i.x===x)?.count||0;
  }
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{ padding: 4 }}>
        <Card noPad>
          <View>
            <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 24, color: theme.page_content.fg, padding: 4, textAlign: "center" }}>{category_data.name}</Text>
            {category_data?.seasonal && <>
              {/* <Text allowFontScaling={false} style={{...font("bold"),fontSize:20,color:theme.page_content.fg,textAlign:"center"}}>{category_data.id}</Text> */}
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{moment(category_data.seasonal.starts).format('L LT')} - {moment(category_data.seasonal.ends).format('L LT')}</Text>
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{t('bouncers:duration',{duration:moment.duration(moment(category_data.seasonal.starts).diff(moment(category_data.seasonal.ends))).humanize()})}</Text>
            </>}
            {parent_datas.map(parent_data => parent_data.id !== "root" ? null : <View style={{ padding: 4, flexDirection: "row", alignItems: "center" }}>
                <IconButton size={24} onPress={() => navigation.push('UserDetails', { username: username })} icon="chevron-left" color={theme.page_content.fg} />
                <Image style={{ borderRadius: 16, height: 32, width: 32, marginHorizontal: 8 }} source={{ uri: parent_data.custom_icon ?? `https://munzee.global.ssl.fastly.net/images/avatars/ua${(user_id || 0).toString(36)}.png` }} />
                <View style={{ flex: 1 }}>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{t('screens:UserDetails')}</Text>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{t(`db:go_back`)}</Text>
                </View>
              </View>)}
            {categories.filter(i => i.parents.includes(category)).filter(i => hasChild(i)).filter(i=>!i.hidden).map(i => <View key={i.id} style={{ padding: 4, flexDirection: "row", alignItems: "center" }}>
              <Image style={{ height: 32, width: 32, marginHorizontal: 8 }} source={getIcon(i.custom_icon ?? i.icon)} />
              <View style={{ flex: 1 }}>
                <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{i.name}</Text>
                <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{i.category ? `#${i.id}` : t(`db:category`)}</Text>
              </View>
              <IconButton size={24} onPress={() => navigation.push('UserCapturesCategory', { username: username, category: i.id })} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
          </View>
        </Card>
      </View>
      {categories.filter(i => i.parents.includes(category)).filter(i => !hasChild(i)).filter(i=>!i.hidden).map(cdata=><View style={{ padding: 4 }}>
        <Card noPad>
          <View>
            <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 24, color: theme.page_content.fg, padding: 4, textAlign: "center" }}>{cdata.name}</Text>
            {cdata?.seasonal && <>
              {/* <Text allowFontScaling={false} style={{...font("bold"),fontSize:20,color:theme.page_content.fg,textAlign:"center"}}>{category_data.id}</Text> */}
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{moment(cdata.seasonal.starts).format('L LT')} - {moment(cdata.seasonal.ends).format('L LT')}</Text>
              <Text allowFontScaling={false} style={{ ...font(), textAlign: "center", color: theme.page_content.fg }}>{t('bouncers:duration',{duration:moment.duration(moment(cdata.seasonal.starts).diff(moment(cdata.seasonal.ends))).humanize()})}</Text>
            </>}
            <View style={{flexDirection:"row",flexWrap:"wrap",justifyContent:"center"}}>
              {types.filter(i => i.category === cdata.id).filter(i=>!i.hidden&&!i.capture_types).map(i => <View key={i.id} style={{ padding: 4, width: 80, alignItems: "center", opacity: get(i.x)>0?1:0.4 }}>
                <Image style={{ height: 32, width: 32, marginHorizontal: 8 }} source={getIcon(i.custom_icon ?? i.icon)} />
                <Text allowFontScaling={false} numberOfLines={1} ellipsizeMode="middle" style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>{i.name}</Text>
                <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{get(i.x).toString()}</Text>
              </View>)}
            </View>
          </View>
        </Card>
      </View>)}
    </ScrollView>
  );
}
Example #28
Source File: index.js    From puente-reactnative-collect with MIT License 4 votes vote down vote up
FindRecords = () => {
  useEffect(() => {
    async function setUserInformation() {
      const storedLimit = await getData('findRecordsLimit');
      const currentLimit = storedLimit === null || storedLimit === undefined ? 2000 : storedLimit;
      const residentData = await getData('residentData');
      const residentDataCount = residentData.length;

      setCurrentData({
        currentLimit,
        residentDataCount
      });
    }
    setUserInformation().then(() => {
      setInputs([
        {
          label: I18n.t('findRecordSettings.currentReccordsStored'),
          value: currentData.residentDataCount,
          key: 'residentDataCount',
          edit: false
        },
        {
          label: I18n.t('findRecordSettings.recordStorageLimit'),
          value: currentData.currentLimit,
          key: 'currentLimit',
          edit: true
        }
      ]);
      setUpdated(false);
    });
  }, [updated]);

  const handleFailedAttempt = () => {
    Alert.alert(
      I18n.t('global.error'),
      I18n.t('findRecordSettings.errorMessage'), [
        { text: I18n.t('global.ok') }
      ],
      { cancelable: true }
    );
  };

  const handleSucccessfullAttempt = () => {
    Alert.alert(
      I18n.t('global.success'),
      I18n.t('findRecordSettings.successMessage'), [
        { text: I18n.t('global.ok') }
      ],
      { cancelable: true }
    );
  };

  const updateUser = async () => {
    setSubmitting(true);

    const newLimit = currentData.currentLimit;

    const submitAction = () => {
      setTimeout(() => {
        setSubmitting(false);
        handleSucccessfullAttempt();
      }, 1000);
    };

    await storeData(newLimit, 'findRecordsLimit').then(() => {
      setUpdated(true);
      submitAction();
    }, (error) => {
      console.log(error); //eslint-disable-line
      setSubmitting(false);
      handleFailedAttempt();
    });
  };

  const updateCurrentData = (key, text) => {
    const copyUserObject = currentData;
    copyUserObject[key] = text;
    setCurrentData(copyUserObject);
  };

  const [currentData, setCurrentData] = useState({});
  const [edit, setEdit] = useState('');
  const [inputs, setInputs] = useState([]);
  const [updated, setUpdated] = useState(false);
  const [submitting, setSubmitting] = useState(false);

  return (
    <View>
      <Headline>{I18n.t('findRecordSettings.findRecords')}</Headline>
      <View style={styles.horizontalLinePrimary} />
      {inputs.length > 0 && inputs.map((result) => (
        <View key={result.key}>
          <Text style={styles.text}>{result.label}</Text>
          <View>
            {edit !== result.key && (
              <View style={styles.textContainer}>
                <Text style={styles.text}>{currentData[result.key]}</Text>
                {result.edit === true && (
                  <Button
                    style={{ marginLeft: 'auto' }}
                    onPress={() => {
                      setEdit(result.key);
                    }}
                  >
                    {I18n.t('findRecordSettings.edit')}
                  </Button>
                )}
              </View>
            )}
            {edit === result.key && (
              <View style={styles.textContainer}>
                <TextInput
                  style={{ flex: 3 }}
                  placeholder={result.value}
                  mode="outlined"
                  onChangeText={(text) => updateCurrentData(result.key, text)}
                />
                <View style={styles.buttonContainer}>
                  <IconButton
                    icon="check"
                    size={25}
                    color={theme.colors.primary}
                    style={styles.svg}
                    onPress={() => {
                      setEdit('');
                    }}
                  />
                  <IconButton
                    icon="window-close"
                    size={25}
                    color={theme.colors.primary}
                    style={styles.svg}
                    onPress={() => {
                      setEdit('');
                    }}
                  />
                </View>
              </View>
            )}
          </View>
          <View style={styles.horizontalLineGray} />

        </View>
      ))}
      {submitting ? (
        <ActivityIndicator
          size="large"
          color={theme.colors.primary}
        />
      ) : (
        <Button onPress={() => updateUser()}>{I18n.t('global.submit')}</Button>
      )}
    </View>
  );
}
Example #29
Source File: index.js    From puente-reactnative-collect with MIT License 4 votes vote down vote up
FormGallery = ({
  navigateToNewRecord, navigateToCustomForm,
  puenteForms,
  pinnedForms, setPinnedForms,
  setLoading, surveyingOrganization
}) => {
  const [customForms, setCustomForms] = useState([]);
  const [workflowData, setWorkflowData] = useState({});
  const [noWorkflowData, setNoWorkflowData] = useState([]);

  useEffect(() => {
    getData('customForms').then((forms) => {
      setCustomForms(forms || []);
      filterWorkflows(forms || []);
    });
  }, [customForms]);

  const filterWorkflows = (forms) => {
    const tableDataByCategory = {};
    forms.forEach((record) => {
      if (!Array.isArray(record.workflows) || record.workflows.length < 1) {
        if ('No Workflow Assigned' in tableDataByCategory) {
          tableDataByCategory['No Workflow Assigned'] = tableDataByCategory['No Workflow Assigned'].concat([record]);
        } else {
          tableDataByCategory['No Workflow Assigned'] = [record];
        }
      } else if (Array.isArray(record.workflows)) {
        record.workflows.forEach((workflow) => {
          if (workflow in tableDataByCategory) {
            tableDataByCategory[workflow] = tableDataByCategory[workflow].concat([record]);
          } else {
            tableDataByCategory[workflow] = [record];
          }
        });
      }
    });
    setNoWorkflowData(tableDataByCategory['No Workflow Assigned']);
    delete tableDataByCategory['No Workflow Assigned'];
    delete tableDataByCategory.Puente;
    setWorkflowData(tableDataByCategory);
  };

  const refreshCustomForms = () => {
    setLoading(true);
    customFormsQuery(surveyingOrganization).then((forms) => {
      setCustomForms(forms);
      setLoading(false);
    });
  };

  const pinForm = async (form) => {
    setPinnedForms([...pinnedForms, form]);
    storeData(pinnedForms, 'pinnedForms');
  };

  const removePinnedForm = async (form) => {
    const filteredPinnedForms = pinnedForms.filter((pinnedForm) => pinnedForm !== form);
    setPinnedForms(filteredPinnedForms);
    storeData(filteredPinnedForms, 'pinnedForms');
  };

  return (
    <View>
      <View key="pinnedForms" style={layout.screenRow}>
        <Text style={styles.header}>{I18n.t('formsGallery.pinnedForms')}</Text>
        <ScrollView horizontal>
          {pinnedForms?.map((form) => (
            <Card
              key={form.objectId ?? form.tag}
              style={layout.cardSmallStyle}
              onPress={() => {
                if (!form.tag) return navigateToCustomForm(form);
                return navigateToNewRecord(form.tag);
              }}
              onLongPress={() => removePinnedForm(form)}
            >

              <View style={styles.cardContainer}>
                {form.image !== undefined && (
                  <form.image height={40} style={styles.svg} />
                )}
                <View style={styles.textContainer}>
                  <Text style={styles.text}>
                    { form.customForm === false ? I18n.t(form.name) : form.name}
                  </Text>
                </View>
              </View>
            </Card>
          ))}
          {pinnedForms?.length < 1 && (
            <View style={layout.screenRow}>
              <Card>
                <Card.Title title={I18n.t('formsGallery.noPinnedForms')} />
              </Card>
            </View>
          )}
        </ScrollView>
      </View>
      <View key="puenteForms" style={layout.screenRow}>
        <Text style={styles.header}>{I18n.t('formsGallery.puenteForms')}</Text>
        <SmallCardsCarousel
          puenteForms={puenteForms}
          navigateToNewRecord={navigateToNewRecord}
          pinForm={pinForm}
          setUser={false}
        />
      </View>
      {/* ALL custom forms */}
      <View key="customForms" style={{ marginHorizontal: 20 }}>
        <View style={{ flexDirection: 'row' }}>
          <Text style={styles.header}>{I18n.t('formsGallery.customForms')}</Text>
          <IconButton
            style={{ bottom: 7 }}
            color={theme.colors.primary}
            size={20}
            icon="refresh"
            onPress={refreshCustomForms}
          />
        </View>
      </View>
      {customForms && (
        <FormsHorizontalView
          forms={customForms}
          navigateToCustomForm={navigateToCustomForm}
          pinForm={pinForm}
        />
      )}
      {/* Workflows */}
      <View key="workflows" style={{ marginHorizontal: 20 }}>
        <View style={{ flexDirection: 'row' }}>
          <Text style={styles.header}>{I18n.t('formsGallery.workflows')}</Text>
          <IconButton
            style={{ bottom: 7 }}
            color={theme.colors.primary}
            size={20}
            icon="refresh"
            onPress={refreshCustomForms}
          />
        </View>
      </View>
      {/* custom forms with workflows */}
      {Object.keys(workflowData).length > 0 && Object.keys(workflowData).map((key) => (
        <FormsHorizontalView
          forms={workflowData[key]}
          header={key}
          navigateToCustomForm={navigateToCustomForm}
          pinForm={pinForm}
        />
      ))}
      {/* custom forms with no workflow assigned */}
      {noWorkflowData && noWorkflowData.length > 0 && (
        <FormsHorizontalView
          forms={noWorkflowData}
          header={I18n.t('formsGallery.noWorflowAssigned')}
          navigateToCustomForm={navigateToCustomForm}
          pinForm={pinForm}
        />
      )}
      <View style={layout.screenRow}>
        <Text style={styles.header}>{I18n.t('formsGallery.marketPlace')}</Text>
      </View>
      <View key="marketplace" style={layout.screenRow}>
        <Card>
          <Card.Content>
            <ComingSoonSVG width={200} height={200} />
            <Title>{I18n.t('formsGallery.ourMarketPlace')}</Title>
            <Paragraph>{I18n.t('formsGallery.discoverForms')}</Paragraph>
            <Button>
              <Text>{I18n.t('formsGallery.exploreForms')}</Text>
            </Button>
          </Card.Content>
        </Card>
      </View>
    </View>
  );
}