diff --git a/src/components/MyLatestReviews.tsx b/src/components/MyLatestReviews.tsx
new file mode 100644
index 0000000..2378ff6
--- /dev/null
+++ b/src/components/MyLatestReviews.tsx
@@ -0,0 +1,96 @@
+import { ActivityIndicator, FlatList, View } from "react-native";
+import { useUser } from "../hooks";
+import { useUserReviews } from "../hooks/useUserReviews";
+import { Card } from "./Card";
+import { StyledText } from "./StyledText";
+import { useScreenInfo } from "../hooks/useScreenInfo";
+import { SmallReviewCard } from "./SmallReviewCard";
+import { useEffect, useMemo } from "react";
+import { usePlatformWideReviews } from "../hooks/usePlatformWideReviews";
+
+export const MyLatestReviews = ({
+ allowPlatformWideReviews = true,
+}: {
+ allowPlatformWideReviews?: boolean;
+}) => {
+ const me = useUser()!;
+ const userReviews = useUserReviews(me.id);
+ const platformWideReviews = usePlatformWideReviews();
+ const { isPhone } = useScreenInfo();
+
+ useEffect(() => {
+ if (
+ userReviews.isFetched &&
+ userReviews.data &&
+ userReviews.data.length == 0 &&
+ !platformWideReviews.isFetched
+ ) {
+ platformWideReviews.refetch();
+ }
+ }, [userReviews.data, userReviews.isFetched, platformWideReviews.isFetched]);
+
+ const displayLoading = useMemo(() => {
+ if (!userReviews.isFetched) {
+ return true;
+ }
+ if (
+ userReviews.data &&
+ userReviews.data.length === 0 &&
+ allowPlatformWideReviews &&
+ !platformWideReviews.isFetched
+ ) {
+ return true;
+ }
+
+ return false;
+ }, [
+ userReviews.data,
+ userReviews.isFetched,
+ allowPlatformWideReviews,
+ platformWideReviews.isFetched,
+ ]);
+
+ const body = useMemo(() => {
+ if (displayLoading) {
+ return ;
+ }
+
+ let reviews = userReviews.data!;
+
+ if (!reviews.length && allowPlatformWideReviews) {
+ reviews = platformWideReviews.data!;
+ }
+
+ if (!reviews.length) {
+ return No reviews to display.;
+ }
+
+ return (
+ (
+
+ )}
+ />
+ );
+ }, [displayLoading, userReviews.data]);
+
+ return (
+ {body}}
+ hideHeaderDivider
+ headerComponent={
+
+ {userReviews.isLoading || platformWideReviews.data?.length
+ ? "Latest reviews"
+ : "My latest reviews"}
+
+ }
+ />
+ );
+};
diff --git a/src/components/ReviewsList.tsx b/src/components/ReviewsList.tsx
deleted file mode 100644
index fcd1568..0000000
--- a/src/components/ReviewsList.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { View, FlatList, ActivityIndicator } from "react-native";
-import { useScreenInfo } from "../hooks/useScreenInfo";
-import { SmallReviewCard } from "./SmallReviewCard";
-import { StyledText } from "./StyledText";
-import { useUserReviews } from "../hooks/useUserReviews";
-
-export const ReviewsList = ({ userId }: { userId: string }) => {
- const reviews = useUserReviews(userId);
- const { isPhone } = useScreenInfo();
-
- if (reviews.isLoading) {
- return ;
- }
-
- return (
-
- {!reviews.isFetched && (
-
- )}
- {reviews.isFetched && !!reviews.data && !reviews.data.length && (
- You have no reviews.
- )}
- {reviews.data && reviews.isFetched && !!reviews.data.length && (
- (
-
- )}
- />
- )}
-
- );
-};
diff --git a/src/hooks/usePlatformWideReviews.ts b/src/hooks/usePlatformWideReviews.ts
new file mode 100644
index 0000000..f24b749
--- /dev/null
+++ b/src/hooks/usePlatformWideReviews.ts
@@ -0,0 +1,11 @@
+import { useQuery } from "@tanstack/react-query";
+import { User } from "../types";
+import { getPlatformWideReviews } from "../utils/api";
+
+export function usePlatformWideReviews() {
+ return useQuery({
+ queryKey: ["latest-reviews"],
+ queryFn: () => getPlatformWideReviews(),
+ enabled: false,
+ });
+}
diff --git a/src/screens/HomeScreen/HomeScreen.tsx b/src/screens/HomeScreen/HomeScreen.tsx
index e54b548..7393822 100644
--- a/src/screens/HomeScreen/HomeScreen.tsx
+++ b/src/screens/HomeScreen/HomeScreen.tsx
@@ -1,15 +1,13 @@
import { View, ScrollView } from "react-native";
import React from "react";
import { DrawerHeader } from "../../components/headers/DrawerHeader";
-import { Card, MyReviewsCard, StyledText } from "../../components";
+import { MyReviewsCard } from "../../components";
import { ConnectionReviewCard } from "../../components/ConnectionsReviewCard";
import { SocialMediaCard } from "../../icons/SocialMediaCard";
import { useUser } from "../../hooks";
-import { ReviewsList } from "../../components/ReviewsList";
+import { MyLatestReviews } from "../../components/MyLatestReviews";
const HomeScreen = ({}: {}) => {
- const user = useUser()!;
-
return (
@@ -17,15 +15,7 @@ const HomeScreen = ({}: {}) => {
- }
- hideHeaderDivider
- headerComponent={
-
- My latest reviews
-
- }
- />
+
diff --git a/src/screens/MyProfileScreen/MyProfileScreen.tsx b/src/screens/MyProfileScreen/MyProfileScreen.tsx
index 6c0e4ff..f397bc4 100644
--- a/src/screens/MyProfileScreen/MyProfileScreen.tsx
+++ b/src/screens/MyProfileScreen/MyProfileScreen.tsx
@@ -1,17 +1,10 @@
-import { View, FlatList, ScrollView, ActivityIndicator } from "react-native";
+import { View, ScrollView } from "react-native";
import React from "react";
import { DrawerHeader } from "../../components/headers/DrawerHeader";
-import {
- Card,
- HorizontalDivider,
- MyReviewsCard,
- ProfileCard,
- StyledText,
-} from "../../components";
+import { HorizontalDivider, ProfileCard } from "../../components";
-import { ReviewsList } from "../../components/ReviewsList";
import { useUser } from "../../hooks";
-import { useUserRatings } from "../../hooks/useUserRatings";
+import { MyLatestReviews } from "../../components/MyLatestReviews";
export const MyProfileScreen = ({}: {}) => {
const me = useUser()!;
@@ -26,15 +19,7 @@ export const MyProfileScreen = ({}: {}) => {
- }
- hideHeaderDivider
- headerComponent={
-
- My latest reviews
-
- }
- />
+
diff --git a/src/utils/api.ts b/src/utils/api.ts
index 9ef4660..cd94993 100644
--- a/src/utils/api.ts
+++ b/src/utils/api.ts
@@ -1,9 +1,15 @@
-import { Connection, User, UserSettings, UserWithCounts, UserWithToken } from '../types';
-import { DbNotification } from '../types/Notification';
-import { Rating } from '../types/Rating';
-import { Review } from '../types/Review';
-import storage from './storage';
-import Base64 from 'Base64';
+import {
+ Connection,
+ User,
+ UserSettings,
+ UserWithCounts,
+ UserWithToken,
+} from "../types";
+import { DbNotification } from "../types/Notification";
+import { Rating } from "../types/Rating";
+import { Review } from "../types/Review";
+import storage from "./storage";
+import Base64 from "Base64";
// @ts-ignore TODO: Fix this
export const baseUrl = process.env.EXPO_PUBLIC_API_BASE_URL;
@@ -18,7 +24,12 @@ type FetchInit = RequestInit;
const enhancedFetch = async (
initialInput: FetchInput,
initialInit: FetchInit,
- preRequestMiddlewares?: Array<(input: FetchInput, init: FetchInit) => { input: FetchInput; init: FetchInit }>,
+ preRequestMiddlewares?: Array<
+ (
+ input: FetchInput,
+ init: FetchInit
+ ) => { input: FetchInput; init: FetchInit }
+ >,
afterRequestMiddlewares?: Array<(before: any) => any>
) => {
const inputWithMiddlewares = (preRequestMiddlewares || []).reduce<{
@@ -30,10 +41,13 @@ const enhancedFetch = async (
});
const result = fetch(inputWithMiddlewares.input, inputWithMiddlewares.init);
- const processedResult = await (afterRequestMiddlewares || []).reduce(async (previosPromise, nextFn) => {
- const prevResult = await previosPromise;
- return nextFn(prevResult);
- }, result);
+ const processedResult = await (afterRequestMiddlewares || []).reduce(
+ async (previosPromise, nextFn) => {
+ const prevResult = await previosPromise;
+ return nextFn(prevResult);
+ },
+ result
+ );
return processedResult;
};
@@ -61,17 +75,20 @@ const normalizeResult = async (response: Response) => {
return responseData;
};
-const authorizedFetch = async (input: FetchInput, init: FetchInit | object): Promise => {
+const authorizedFetch = async (
+ input: FetchInput,
+ init: FetchInit | object
+): Promise => {
const token = await storage.getItem(storage.TOKEN_KEY);
- console.log('token is ', token);
+ console.log("token is ", token);
return enhancedFetch(
input,
init,
[
addHeaders({
- 'Content-Type': 'application/json',
+ "Content-Type": "application/json",
Authorization: `Bearer ${token}`,
}),
stringifyBody(),
@@ -84,10 +101,10 @@ export type SignupInput = {
email: string;
};
-export async function signUp(email: SignupInput['email']): Promise {
+export async function signUp(email: SignupInput["email"]): Promise {
const response = await fetch(signUpUrl, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
const responseData = await response.json();
@@ -95,7 +112,7 @@ export async function signUp(email: SignupInput['email']): Promise {
if (response.ok) {
return responseData;
} else if (response.status === 409) {
- throw new Error('There is already an account with this email.');
+ throw new Error("There is already an account with this email.");
} else {
throw new Error(responseData.message);
}
@@ -105,10 +122,10 @@ export type SigninInput = {
email: string;
};
-export async function signIn(email: SigninInput['email']): Promise {
+export async function signIn(email: SigninInput["email"]): Promise {
const response = await fetch(signInUrl, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
const responseData = await response.json();
@@ -125,12 +142,12 @@ export type VerifyEmailInput = {
};
export async function verifyEmail(
- email: VerifyEmailInput['email'],
- code: VerifyEmailInput['code']
+ email: VerifyEmailInput["email"],
+ code: VerifyEmailInput["code"]
): Promise {
const response = await fetch(verifyEmailUrl, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, code }),
});
const responseData = await response.json();
@@ -142,13 +159,16 @@ export async function verifyEmail(
}
export async function getSearchUserResult(query: string) {
- return authorizedFetch(`${baseUrl}/connections/search/${encodeURIComponent(query)}`, {
- method: 'GET',
- });
+ return authorizedFetch(
+ `${baseUrl}/connections/search/${encodeURIComponent(query)}`,
+ {
+ method: "GET",
+ }
+ );
}
export async function getMe(): Promise {
- return authorizedFetch(`${baseUrl}/user`, { method: 'GET' });
+ return authorizedFetch(`${baseUrl}/user`, { method: "GET" });
}
export type RegenerateCodeInput = {
@@ -156,7 +176,7 @@ export type RegenerateCodeInput = {
};
export async function regenerateCode(data: RegenerateCodeInput) {
return enhancedFetch(`${baseUrl}/auth/regenerate-code/${data.email}`, {
- method: 'PUT',
+ method: "PUT",
});
}
@@ -168,74 +188,87 @@ export type UpdateProfileData = {
export async function updateProfileData(data: UpdateProfileData) {
return authorizedFetch(`${baseUrl}/user`, {
- method: 'PUT',
+ method: "PUT",
body: data,
});
}
export async function updateProfilePicture(uri: string) {
return authorizedFetch(`${baseUrl}/user/profile-picture`, {
- method: 'PUT',
+ method: "PUT",
body: { file: uri },
});
}
-export async function getConnection(userId: User['id']): Promise {
+export async function getConnection(userId: User["id"]): Promise {
return authorizedFetch(`${baseUrl}/connections/${userId}`, {
- method: 'GET',
+ method: "GET",
});
}
-export async function getUserAvgRatings(userId: User['id']): Promise {
+export async function getUserAvgRatings(userId: User["id"]): Promise {
return authorizedFetch(`${baseUrl}/reviews/avg-rating/${userId}`, {
- method: 'GET',
+ method: "GET",
});
}
-export async function getUserReviews(userId: User['id']): Promise {
+export async function getUserReviews(userId: User["id"]): Promise {
return authorizedFetch(`${baseUrl}/reviews/${userId}`, {
- method: 'GET',
+ method: "GET",
});
}
-export async function likeReview(reviewId: Review['id']): Promise {
+export async function likeReview(reviewId: Review["id"]): Promise {
return authorizedFetch(`${baseUrl}/reviews/${reviewId}/like`, {
- method: 'POST',
+ method: "POST",
});
}
-export async function unlikeReview(reviewId: Review['id']): Promise {
+export async function unlikeReview(reviewId: Review["id"]): Promise {
return authorizedFetch(`${baseUrl}/reviews/${reviewId}/like`, {
- method: 'DELETE',
+ method: "DELETE",
});
}
+export async function getPlatformWideReviews(): Promise {
+ return authorizedFetch(`${baseUrl}/reviews/latest`, { method: "GET" });
+}
+
export async function getConnections(): Promise {
return authorizedFetch(`${baseUrl}/connections`, {
- method: 'GET',
+ method: "GET",
});
}
-export async function getSuggestedForReviewConnections(): Promise {
+export async function getSuggestedForReviewConnections(): Promise<
+ Connection[]
+> {
return authorizedFetch(`${baseUrl}/connections`, {
- method: 'GET',
+ method: "GET",
});
}
-export async function connectWithUser(userId: Connection['id']): Promise {
+export async function connectWithUser(
+ userId: Connection["id"]
+): Promise {
return authorizedFetch(`${baseUrl}/connections/connect/${userId}`, {
- method: 'POST',
+ method: "POST",
});
}
-export async function unconnectWithUser(userId: Connection['id']): Promise {
+export async function unconnectWithUser(
+ userId: Connection["id"]
+): Promise {
return authorizedFetch(`${baseUrl}/connections/connect/${userId}`, {
- method: 'DELETE',
+ method: "DELETE",
});
}
export async function searchByUserLink(link: string): Promise {
- return authorizedFetch(`${baseUrl}/connections/search-by-external-profile/${Base64.btoa(link)}`, { method: 'GET' });
+ return authorizedFetch(
+ `${baseUrl}/connections/search-by-external-profile/${Base64.btoa(link)}`,
+ { method: "GET" }
+ );
}
export type SendReviewData = {
@@ -248,7 +281,7 @@ export type SendReviewData = {
export async function sendReview(ratedUserId: string, data: SendReviewData) {
return authorizedFetch(`${baseUrl}/reviews`, {
- method: 'POST',
+ method: "POST",
body: {
postedToId: ratedUserId,
review: data,
@@ -258,57 +291,62 @@ export async function sendReview(ratedUserId: string, data: SendReviewData) {
export async function getMyReviewForUser(userId: string): Promise {
return authorizedFetch(`${baseUrl}/reviews/my-review/${userId}`, {
- method: 'GET',
+ method: "GET",
});
}
export async function deleteReview(reviewId: string) {
return authorizedFetch(`${baseUrl}/reviews/${reviewId}`, {
- method: 'DELETE',
+ method: "DELETE",
});
}
-export async function updateReview(reviewId: string, reviewData: SendReviewData): Promise {
+export async function updateReview(
+ reviewId: string,
+ reviewData: SendReviewData
+): Promise {
return authorizedFetch(`${baseUrl}/reviews/${reviewId}`, {
- method: 'PUT',
+ method: "PUT",
body: reviewData,
});
}
export async function addPushToken(token: string) {
return authorizedFetch(`${baseUrl}/notifications/token`, {
- method: 'POST',
+ method: "POST",
body: { token },
});
}
export async function getNotifications(): Promise {
- return authorizedFetch(`${baseUrl}/notifications`, { method: 'GET' });
+ return authorizedFetch(`${baseUrl}/notifications`, { method: "GET" });
}
export async function getReviewsPostedByMe(): Promise {
- return authorizedFetch(`${baseUrl}/reviews/posted`, { method: 'GET' });
+ return authorizedFetch(`${baseUrl}/reviews/posted`, { method: "GET" });
}
export async function getReviewdUsers(): Promise {
- return authorizedFetch(`${baseUrl}/connections/reviewed`, { method: 'GET' });
+ return authorizedFetch(`${baseUrl}/connections/reviewed`, { method: "GET" });
}
export async function getUserSettings(): Promise {
- return authorizedFetch(`${baseUrl}/user/settings`, { method: 'GET' });
+ return authorizedFetch(`${baseUrl}/user/settings`, { method: "GET" });
}
export type UpdateUserSettingsData = {
reviewsVisible?: boolean;
anonymous?: boolean;
};
-export async function updateUserSettings(data: UpdateUserSettingsData): Promise {
+export async function updateUserSettings(
+ data: UpdateUserSettingsData
+): Promise {
return authorizedFetch(`${baseUrl}/user/settings`, {
- method: 'PUT',
+ method: "PUT",
body: data,
});
}
export async function deleteAccount() {
- return authorizedFetch(`${baseUrl}/user`, { method: 'DELETE' });
+ return authorizedFetch(`${baseUrl}/user`, { method: "DELETE" });
}