Skip to content

Commit

Permalink
Merge pull request #100 from SustenTerra/feat/select-state
Browse files Browse the repository at this point in the history
feat: add state selector component
  • Loading branch information
davigps authored Jul 31, 2024
2 parents f683551 + 838bec2 commit 61d7e1c
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 19 deletions.
31 changes: 20 additions & 11 deletions app/posts/(with-tab)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Input from '@/components/Input';
import Loading from '@/components/Loading';
import PostCard from '@/components/PostCard';
import ScrollablePage from '@/components/ScrollablePage';
import StateSelector from '@/components/StateSelector';
import Text from '@/components/Text';
import { TitleContainer } from '@/components/pages/courses/styles';
import {
Expand All @@ -21,6 +22,7 @@ import {
PostsContainer,
PostsGridHeader,
SearchWrapper,
HeaderWrapper,
} from '@/components/pages/posts/styles';
import { ProfileInfo } from '@/components/pages/profile';
import { usePostSorting, usePosts } from '@/hooks/posts';
Expand All @@ -36,6 +38,7 @@ export default function Posts() {
search: string;
category: string;
userId: string;
selectedState: string;
}>();

const [categories, setCategories] = useState<string[]>(DEFAULT_CATEGORIES);
Expand All @@ -46,10 +49,12 @@ export default function Posts() {
const [selectedCategory, setSelectedCategory] = useState(
categories.indexOf(params.category || DEFAULT_CATEGORIES[0]),
);

const { loadingPosts, viewPosts } = usePosts(
params.category,
params.search,
params.userId,
params.selectedState,
);
const sorting = usePostSorting(viewPosts);

Expand Down Expand Up @@ -99,17 +104,21 @@ export default function Posts() {
return (
<ScrollablePage>
<Container>
<Link asChild replace href="/">
<Header>
<Image
style={{ width: 50, height: 50 }}
source={require('assets/adaptive-icon.png')}
/>
<Text size="h1" color="primary" weight="bold">
SustenTerra
</Text>
</Header>
</Link>
<Header>
<Link asChild replace href="/">
<HeaderWrapper>
<Image
style={{ width: 50, height: 50 }}
source={require('assets/adaptive-icon.png')}
/>
<Text size="h1" color="primary" weight="bold">
SustenTerra
</Text>
</HeaderWrapper>
</Link>

<StateSelector />
</Header>

{!params.userId && (
<SearchWrapper>
Expand Down
103 changes: 103 additions & 0 deletions app/posts/(with-tab)/select-state.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import Feather from '@expo/vector-icons/Feather';
import { useRouter } from 'expo-router';
import React, { useState, useRef, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import RNPickerSelect from 'react-native-picker-select';
import { useTheme, DefaultTheme } from 'styled-components/native';
import { brazilianStatesList, StateAcronym } from 'utils/brazilianStatesList';

import BackButton from '@/components/BackButton';

export default function StateSelector() {
const router = useRouter();
const [selectedState, setSelectedState] = useState('Todos');
const theme = useTheme();
const ref = useRef<RNPickerSelect>(null);

const handleChange = (value: string) => {
setSelectedState(value);
router.push(`/posts?selectedState=${value}`);
};

useEffect(() => {
if (selectedState === 'Todos' && brazilianStatesList.length > 0) {
setSelectedState(brazilianStatesList[0].acronym);
}
}, [selectedState, brazilianStatesList]);

return (
<View style={styles.container}>
<BackButton defaultRoute="/posts" />
<View style={styles.pickerContainer}>
<Feather name="map-pin" size={24} color={theme.colors.textBody} />
<RNPickerSelect
ref={ref}
style={pickerSelectStyles(theme)}
placeholder={{
label: 'Selecione um Estado',
value: '',
}}
doneText="Selecionar"
onValueChange={handleChange}
items={brazilianStatesList.map((state: StateAcronym) => ({
label: state.name,
value: state.acronym,
}))}
/>
</View>
</View>
);
}

const pickerSelectStyles = (theme: DefaultTheme) =>
StyleSheet.create({
viewContainer: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 20,
backgroundColor: 'white',
},
inputIOSContainer: {
flex: 1,
},
inputIOS: {
fontSize: 16,
paddingVertical: 12,
},
inputWeb: {
borderWidth: 0,
fontSize: 16,
paddingVertical: 12,
},
inputAndroid: {
fontSize: 16,
paddingVertical: 12,
},
inputAndroidContainer: {
flex: 1,
},
placeholder: {
color: theme.colors.textBody,
},
});

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#F5F1F0',
},
pickerContainer: {
flexDirection: 'row',
alignItems: 'center',
borderRadius: 10,
borderWidth: 1,
borderColor: '#dcdcdc',
padding: 8,
marginTop: 16,
width: '100%',
backgroundColor: 'white',
},
});
1 change: 1 addition & 0 deletions app/profile/my-posts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default function MyPosts() {
undefined,
undefined,
auth.user ? String(auth.user.id) : undefined,
undefined,
);

const shareLink = `https://sustenterra.netlify.app/posts?userId=${auth.user?.id}`;
Expand Down
27 changes: 27 additions & 0 deletions components/StateSelector/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Feather from '@expo/vector-icons/Feather';
import { Link, useLocalSearchParams } from 'expo-router';
import { useTheme } from 'styled-components/native';

import { Container, StateText } from './styles';

export default function StateSelector() {
const theme = useTheme();

const { selectedState } = useLocalSearchParams<{
selectedState: string;
}>();

const label = selectedState || 'Todos';

return (
<Link href="/posts/select-state">
<Container>
<Feather name="map-pin" size={20} color={theme.colors.secondary} />

<StateText color="secondary" weight="bold">
{label}
</StateText>
</Container>
</Link>
);
}
36 changes: 36 additions & 0 deletions components/StateSelector/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import styled from 'styled-components/native';

import Text from '../Text';

import { horizontalScale, moderateScale, verticalScale } from '@/utils/scale';

export const Container = styled.TouchableOpacity`
flex-direction: row;
align-items: center;
gap: ${horizontalScale(5)}px;
padding: ${verticalScale(10)}px ${horizontalScale(15)}px;
background-color: ${(props) => props.theme.colors.light};
border-radius: 100px;
`;

export const StateText = styled(Text)``;

export const StatesList = styled.ScrollView`
padding: ${verticalScale(10)}px 0;
top: 100px;
z-index: 1;
`;

interface ButtonProps {
active: boolean;
}

export const Button = styled.TouchableOpacity<ButtonProps>`
height: ${verticalScale(40)}px;
padding: ${moderateScale(10)}px ${moderateScale(20)}px;
border-radius: ${moderateScale(40)}px;
margin-right: ${horizontalScale(10)}px;
background-color: ${(props) =>
props.active ? props.theme.colors.primary : props.theme.colors.light};
`;
9 changes: 9 additions & 0 deletions components/pages/posts/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ export const Container = styled.SafeAreaView`
`;

export const Header = styled.View`
width: 100%;
flex-direction: row;
gap: ${horizontalScale(5)}px;
align-items: center;
justify-content: space-between;
padding: 0 ${horizontalScale(10)}px;
`;

export const HeaderWrapper = styled.View`
flex-direction: row;
gap: ${horizontalScale(5)}px;
align-items: center;
Expand Down
44 changes: 36 additions & 8 deletions hooks/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ interface GetPostsPayload {
search?: string;
category?: string;
userId?: string;
selectedState?: string;
}

const cacheService = new PostsCacheService();

async function listCachedPosts({ search, category, userId }: GetPostsPayload) {
async function listCachedPosts({
search,
category,
userId,
selectedState,
}: GetPostsPayload) {
const posts = await cacheService.get();

showMessage({
Expand All @@ -29,6 +35,10 @@ async function listCachedPosts({ search, category, userId }: GetPostsPayload) {

return (
posts?.filter((post) => {
if (selectedState && post.location !== selectedState) {
return false;
}

if (search && !post.title.toLowerCase().includes(search.toLowerCase())) {
return false;
}
Expand All @@ -46,16 +56,25 @@ async function listCachedPosts({ search, category, userId }: GetPostsPayload) {
);
}

async function fetchPosts({ search, category, userId }: GetPostsPayload) {
async function fetchPosts({
search,
category,
userId,
selectedState,
}: GetPostsPayload) {
const networkState = await Network.getNetworkStateAsync();

if (networkState.isConnected) {
const posts = await client.posts.listAllPostsPostsGet(
let posts = await client.posts.listAllPostsPostsGet(
search,
userId ? Number(userId) : undefined,
category,
);

if (selectedState) {
posts = posts.filter((post) => post.location === selectedState);
}

await cacheService.set(posts);

return posts;
Expand All @@ -68,17 +87,24 @@ export function usePosts(
category: string | undefined,
search: string | undefined,
userId: string | undefined,
selectedState: string | undefined,
) {
const [loadingPosts, setLoadingPosts] = useState(true);
const [viewPosts, setViewPosts] = useState<PostView[]>([]);

const getPosts = async ({ search, category, userId }: GetPostsPayload) => {
const getPosts = async ({
search,
category,
userId,
selectedState,
}: GetPostsPayload) => {
try {
setLoadingPosts(true);
const posts = await fetchPosts({
search,
category,
userId,
selectedState,
});
setViewPosts(posts);
} catch (error) {
Expand All @@ -91,13 +117,15 @@ export function usePosts(
const getPostsDebounced = useCallback(debounce(getPosts, 500), []);

useEffect(() => {
console.log(selectedState);

if (search) {
getPostsDebounced({ search });
getPostsDebounced({ search, selectedState });
return;
}

if (category && category !== 'Todos') {
getPosts({ category });
getPosts({ category, selectedState });
return;
}

Expand All @@ -106,8 +134,8 @@ export function usePosts(
return;
}

getPostsDebounced({});
}, [search, category, userId]);
getPostsDebounced({ selectedState });
}, [search, category, userId, selectedState]);

return {
loadingPosts,
Expand Down

0 comments on commit 61d7e1c

Please sign in to comment.