Skip to content

Commit

Permalink
Merge pull request #2 from Delemangi/improvement/ui
Browse files Browse the repository at this point in the history
Improve UI
  • Loading branch information
alekjarmov authored Feb 11, 2024
2 parents 2e34d14 + 2b398ef commit 9697230
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 78 deletions.
1 change: 1 addition & 0 deletions src/api/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useGetPosts = (type: string | null) => {
fetch(getUrl(type!))
.then((res) => res.json())
.then((data) => data.posts),
select: (data) => data.reverse(),
staleTime: 1000 * 60 * 5,
});
};
Expand Down
42 changes: 35 additions & 7 deletions src/app/(app)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
import { useGetPosts } from "@api/hooks";
import { isRouteAuthenticated } from "@auth/routes";
import LoadingSpinner from "@components/LoadingSpinner";
import { PostCard } from "@components/PostCard";
import { Text, makeStyles } from "@rneui/themed";
import { usePostStore } from "@stores/postStore";
import { useUserStore } from "@stores/userStore";
import { usePathname } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { ScrollView } from "react-native";
import { Redirect, usePathname } from "expo-router";
import { ScrollView, View } from "react-native";

import Login from "./login";
const useStyles = makeStyles((theme) => ({
container: {
display: "flex",
justifyContent: "center",
alignItems: "center",
marginTop: 20,
},
text: {
color: theme.colors.white,
},
loadingSpinner: {
marginTop: 20,
},
}));

const App = () => {
const styles = useStyles();
const { user } = useUserStore();
const route = usePathname();
const postsType = usePostStore((state) => state.type);
const { data } = useGetPosts(postsType);

if (!user && isRouteAuthenticated(route)) {
return <Login />;
return <Redirect href="/login" />;
}

return (
<ScrollView>
<StatusBar style="auto" />
{data?.map((post) => <PostCard key={post.url} post={post} />)}
{postsType &&
data &&
data.map((post) => <PostCard key={post.url} post={post} />)}

{postsType && !data && (
<View style={styles.loadingSpinner}>
<LoadingSpinner size="large" />
</View>
)}

{!postsType && (
<View style={styles.container}>
<Text style={styles.text}>Please select a type!</Text>
</View>
)}
</ScrollView>
);
};
Expand Down
18 changes: 8 additions & 10 deletions src/app/(app)/login.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useLoginUser } from "@auth/hooks";
import ErrorScreen from "@components/ErrorScreen";
import LoadingSpinner from "@components/LoadingSpinner";
import LoginField from "@components/LoginField";
import { Redirect } from "expo-router";
import { useState } from "react";
Expand All @@ -14,13 +12,11 @@ const Login = () => {
return <Redirect href="/" />;
}

if (loading) {
return <LoadingSpinner />;
}

if (error) {
return <ErrorScreen error={error.message} />;
}
const isDisabled =
!email ||
!password ||
!/^[^@]+@[^@]+\.[^@]+$/g.test(email) ||
password.length < 5;

return (
<LoginField
Expand All @@ -29,8 +25,10 @@ const Login = () => {
onEmailChange={setEmail}
password={password}
onPasswordChange={setPassword}
disabled={!email || !password}
disabled={isDisabled}
onButtonClick={() => login(email, password)}
isLoading={loading ?? false}
error={error}
/>
);
};
Expand Down
12 changes: 12 additions & 0 deletions src/app/(app)/logout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useLogoutUser } from "@auth/hooks";
import { Redirect } from "expo-router";

const Logout = () => {
const { logout } = useLogoutUser();

logout();

return <Redirect href="/" />;
};

export default Logout;
18 changes: 8 additions & 10 deletions src/app/(app)/register.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useRegisterUser } from "@auth/hooks";
import ErrorScreen from "@components/ErrorScreen";
import LoadingSpinner from "@components/LoadingSpinner";
import LoginField from "@components/LoginField";
import { Redirect } from "expo-router";
import { useState } from "react";
Expand All @@ -14,13 +12,11 @@ const Register = () => {
return <Redirect href="/" />;
}

if (loading) {
return <LoadingSpinner />;
}

if (error) {
return <ErrorScreen error={error.message} />;
}
const isDisabled =
!email ||
!password ||
!/^[^@]+@[^@]+\.[^@]+$/g.test(email) ||
password.length < 5;

return (
<LoginField
Expand All @@ -29,8 +25,10 @@ const Register = () => {
onEmailChange={setEmail}
password={password}
onPasswordChange={setPassword}
disabled={!email || !password}
disabled={isDisabled}
onButtonClick={() => register(email, password)}
isLoading={loading ?? false}
error={error}
/>
);
};
Expand Down
7 changes: 7 additions & 0 deletions src/auth/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { queryClient } from "@api/queryClient";
import { firebaseApp } from "@auth/firebase";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { usePostStore } from "@stores/postStore";
import { useUserStore } from "@stores/userStore";
import {
createUserWithEmailAndPassword,
Expand Down Expand Up @@ -64,6 +66,7 @@ export const useLogoutUser = () => {
const { setUser } = useUserStore();
const [loading, setLoading] = useState<boolean | null>(null);
const [error, setError] = useState<Error | null>(null);
const setType = usePostStore((state) => state.setType);

const logout = useCallback(() => {
setLoading(true);
Expand All @@ -72,7 +75,11 @@ export const useLogoutUser = () => {
.signOut()
.then(() => {
setUser(null);
setType(null);
setLoading(false);
queryClient.invalidateQueries({
predicate: (query) => query.queryKey[0] === "posts",
});
})
.catch((error) => {
setError(error);
Expand Down
73 changes: 57 additions & 16 deletions src/components/AppHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,91 @@
import { Header, Text, makeStyles } from "@rneui/themed";
import { useLogoutUser } from "@auth/hooks";
import { Button, Chip, Header, Text, makeStyles } from "@rneui/themed";
import { usePostStore } from "@stores/postStore";
import { useUserStore } from "@stores/userStore";
import React from "react";
import { ScrollView, TouchableOpacity } from "react-native";
import { ScrollView } from "react-native";

const useStyles = makeStyles((theme) => ({
headerContainer: {
backgroundColor: theme.colors.primary,
justifyContent: "space-around",
height: 100,
},
scrollView: {
flexGrow: 0,
},
option: {
paddingHorizontal: 10,
},
optionText: {
color: theme.colors.white,
},
loginText: {
color: theme.colors.white,
},
chip: {
marginHorizontal: 5,
},
selectedChip: {
borderStyle: "solid",
borderWidth: 1,
borderColor: theme.colors.white,
},
}));

const AppHeader = () => {
const styles = useStyles();
const { setType, types } = usePostStore((state) => state);
const {
setType,
types: postTypes,
type: selectedType,
} = usePostStore((state) => state);
const user = useUserStore((state) => state.user);
const { logout, loading } = useLogoutUser();

const handlePostTypeSelect = (type: string) => {
setType(type);
};

return (
<Header
leftComponent={
user ? (
<Button
icon={{
name: "logout",
type: "material",
color: "white",
}}
onPress={() => {
logout();
}}
loading={Boolean(loading)}
type="solid"
/>
) : undefined
}
centerComponent={
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.scrollView}
alwaysBounceHorizontal
>
{types.map((type, index) => (
<TouchableOpacity
key={index}
onPress={() => handlePostTypeSelect(type)}
style={styles.option}
>
<Text style={styles.optionText}>{type.toUpperCase()}</Text>
</TouchableOpacity>
))}
{user ? (
postTypes.map((postType) => (
<Chip
key={postType}
containerStyle={[
styles.chip,
selectedType === postType && styles.selectedChip,
]}
title={postType.toUpperCase()}
type={selectedType === postType ? "outline" : "solid"}
titleStyle={styles.optionText}
onPress={() => handlePostTypeSelect(postType)}
size="md"
/>
))
) : (
<Text style={styles.loginText}>Please login to see posts!</Text>
)}
</ScrollView>
}
containerStyle={styles.headerContainer}
Expand Down
8 changes: 7 additions & 1 deletion src/components/ErrorScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const useStyles = makeStyles((theme) => ({
margin: "auto",
color: theme.colors.error,
},
message: {
color: theme.colors.white,
marginBottom: theme.spacing.xl,
},
}));

type Props = {
Expand All @@ -24,7 +28,9 @@ const ErrorScreen = ({ error }: Props) => {

return (
<View style={styles.container}>
<Text h3>The application has crashed.</Text>
<Text h4 style={styles.message}>
The application has crashed :'(
</Text>
<Text style={styles.errorText}>{error}</Text>
</View>
);
Expand Down
Loading

0 comments on commit 9697230

Please sign in to comment.