Skip to content

Commit

Permalink
feat(mobile): add follow tag feature
Browse files Browse the repository at this point in the history
  • Loading branch information
atakanyasar committed Dec 10, 2024
1 parent 5740867 commit c0ee434
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 14 deletions.
39 changes: 25 additions & 14 deletions mobile/app/tags/[tagId].tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ErrorAlert from "@/components/ErrorAlert";
import FollowTagButton from "@/components/FollowTagButton";
import { FullscreenLoading } from "@/components/FullscreenLoading";
import { QuestionList } from "@/components/QuestionsList";
import {
Expand Down Expand Up @@ -30,13 +31,14 @@ import useAuthStore from "@/services/auth";
import { Link, router, useLocalSearchParams } from "expo-router";
import { ArrowLeftIcon, ChevronDownIcon, Plus } from "lucide-react-native";
import { useState } from "react";
import { SvgUri } from "react-native-svg";

export default function TagPage() {
const { tagId } = useLocalSearchParams<{ tagId: string }>();

const { data, isLoading, error } = useGetTagDetails(
{
pathParams: { tagId: tagId! },
pathParams: { tagId: Number(tagId) },
},
{
enabled: !!tagId,
Expand Down Expand Up @@ -68,34 +70,43 @@ export default function TagPage() {
}

return (
<VStack className="flex-1 px-2 my-8 mt-8">
<VStack className="flex-1 px-2 my-8">
<HStack className="flex items-center justify-between">
<Button
onPress={() => router.back()}
className="self-start mt-4 ml-2"
className="self-start mt-12 ml-2"
variant={"outline"}
size="sm"
>
<Icon as={ArrowLeftIcon} />
</Button>
</HStack>
<ScrollView contentContainerStyle={{ paddingVertical: 32, flexGrow: 1 }}>
<View className="flex items-start px-4">
{tag?.logoImage && tag.logoImage.endsWith(".svg") && (
<SvgUri
uri={tag?.logoImage}
viewBox="0 0 480 240"
width="120px"
height= "90px"
/>
)}

{tag?.logoImage && tag.logoImage.endsWith(".png") && (
<Image
source={{ uri: tag?.logoImage || "https://placehold.co/400x300" }}
style={{ width: 400, height: 300 }}
/>
)}
</View>

<View style={{ paddingHorizontal: 16, gap: 16 }}>
<HStack
style={{ alignItems: "center", justifyContent: "space-between" }}
>
<Text className="text-2xl font-bold">{tag.name}</Text>
<FollowTagButton tag={{id: Number(tagId), selfFollowing: tag.following}} />
</HStack>
<Image
source={{ uri: tag?.logoImage || "https://placehold.co/400x300" }}
alt={tag.name}
style={{
height: 192,
width: "100%",
borderRadius: 24,
resizeMode: "contain",
}}
/>
<Text>{tag.description}</Text>

<VStack style={{ marginTop: 16, gap: 16 }}>
Expand Down Expand Up @@ -155,7 +166,7 @@ export default function TagPage() {

<QuestionList
searchQueryParams=""
tagFilter={tag.tagId}
tagFilter={tag.tagId.toString()}
{...(difficultyFilter ? { difficultyFilter } : {})}
sortBy={tab === "top-rated" ? "TOP_RATED" : "RECENT"}
/>
Expand Down
94 changes: 94 additions & 0 deletions mobile/components/FollowTagButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {
useFollowTag,
useGetTagDetails,
useUnfollowTag,
} from "@/services/api/programmingForumComponents";
import { useEffect, useState } from "react";
import { Button, ButtonText } from "./ui/button";

export default function FollowTagButton({
tag,
}: {
tag: { id?: number; selfFollowing?: boolean };
}) {
const { isLoading, data, error, refetch } = useGetTagDetails(
{
pathParams: {
tagId: tag.id!,
},
},
);


const [optimisticFollowing, setOptimisticFollowing] = useState(
false
);

useEffect(() => {
setOptimisticFollowing(tag.selfFollowing ?? false);
}, [tag.selfFollowing]);

const { mutateAsync: follow } = useFollowTag({
onMutate: async () => {
setOptimisticFollowing(true);
},
onSuccess: (data) => {
refetch().then(() => {
setOptimisticFollowing(true);
});
console.log(data);
},
onError: (error) => {
console.error(error);
setOptimisticFollowing(false);
},
});

const { mutateAsync: unfollow } = useUnfollowTag({
onMutate: async () => {
setOptimisticFollowing(false);
},
onSuccess: () => {
refetch().then(() => {
setOptimisticFollowing(false);
});
},
onError: () => {
setOptimisticFollowing(true);
},
});

const following = optimisticFollowing ?? data?.data?.following;

return (
<Button
disabled={!!error || isLoading}
variant={following && !isLoading ? "outline" : "solid"}
onPress={() => {
if (following) {
unfollow({
pathParams: {
tagId: tag.id!,
},
});
} else {
follow({
pathParams: {
tagId: tag.id!,
},
});
}
}}
>
<ButtonText>
{isLoading
? "Loading..."
: error
? "Error"
: following
? "Following"
: "Follow"}
</ButtonText>
</Button>
);
}

0 comments on commit c0ee434

Please sign in to comment.