Skip to content

Commit 1d78ae4

Browse files
committed
add first post prompt
1 parent 2e8deaa commit 1d78ae4

4 files changed

Lines changed: 96 additions & 6 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Box } from "@/components/shared/dashboard";
2+
import { Button } from "@codevs/ui";
3+
import { Sparkles, PlusCircle } from "lucide-react";
4+
5+
interface FirstPostPromptProps {
6+
onCreatePost: () => void;
7+
}
8+
9+
export default function FirstPostPrompt({
10+
onCreatePost,
11+
}: FirstPostPromptProps) {
12+
return (
13+
<Box className="group relative flex h-[340px] cursor-pointer flex-col justify-center rounded-xl p-6 transition hover:shadow-md">
14+
<div className="flex flex-col items-center text-center">
15+
<div className="mb-4 flex h-14 w-14 items-center justify-center rounded-full bg-primary/10">
16+
<Sparkles className="h-7 w-7 text-primary" />
17+
</div>
18+
19+
<h2 className="mb-2 text-xl font-semibold text-gray-800 dark:text-gray-100">
20+
Create your first post
21+
</h2>
22+
23+
<p className="mb-6 max-w-xs text-sm text-gray-500 dark:text-gray-400">
24+
Share something with the community and earn social points for your
25+
first post 🚀
26+
</p>
27+
28+
<button
29+
onClick={onCreatePost}
30+
className="inline-flex items-center gap-2 rounded-lg bg-primary px-5 py-2.5 text-sm font-semibold text-white transition hover:bg-primary/90"
31+
>
32+
<PlusCircle className="h-4 w-4" />
33+
Create Post
34+
</button>
35+
</div>
36+
</Box>
37+
);
38+
}

‎apps/codebility/app/home/feeds/_components/SocialPointsCard.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default function SocialPointsCard() {
3333
}, [user, posts]);
3434

3535
return (
36-
<div className="dark:bg-white/3 relative mt-4 w-full rounded-xl border border-white/10 bg-gray-800 p-4 text-white shadow-lg backdrop-blur-sm transition-all duration-300 hover:scale-[1.02] hover:bg-white/10 hover:shadow-lg dark:border-white/5 xl:fixed xl:right-6 xl:top-20 xl:z-50 xl:mt-0 xl:w-64">
36+
<div className="dark:bg-white/3 relative mt-4 mb-4 w-full rounded-xl border border-white/10 bg-gray-800 p-4 text-white shadow-lg backdrop-blur-sm transition-all duration-300 hover:scale-[1.02] hover:bg-white/10 hover:shadow-lg dark:border-white/5 xl:fixed xl:right-6 xl:top-20 xl:z-50 xl:mt-0 xl:w-64">
3737
<div className="relative">
3838
<div className="mb-3 flex items-center justify-between">
3939
<div className="flex items-center gap-2">

‎apps/codebility/app/home/feeds/_services/action.ts‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,4 +600,26 @@ export const hasReachedDailyPostLimit = async (author_id: string, limit = 2) =>
600600
console.error("Error in hasReachedDailyPostLimit:", error);
601601
throw error;
602602
}
603-
};
603+
};
604+
605+
export const hasNotPostedYet = async (user_id: string) => {
606+
try {
607+
const supabase = await createClientServerComponent();
608+
609+
const { count, error } = await supabase
610+
.from("posts")
611+
.select("id", { count: "exact", head: true })
612+
.eq("author_id", user_id);
613+
614+
if (error) {
615+
console.error("Error checking if user has posted:", error);
616+
throw error;
617+
}
618+
619+
// Return true if user has zero posts
620+
return (count ?? 0) === 0;
621+
} catch (error) {
622+
console.error("Error in hasNotPostedYet:", error);
623+
throw error;
624+
}
625+
};

‎apps/codebility/app/home/feeds/page.tsx‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import Feed from "./_components/Feed";
99
import SocialPointsCard from "./_components/SocialPointsCard";
1010
import SortMenu from "./_components/SortMenu";
1111
import { SEARCH_DEBOUNCE_MS } from "./_constants";
12-
import { getUserRole, hasReachedDailyPostLimit } from "./_services/action";
12+
import { getUserRole, hasNotPostedYet, hasReachedDailyPostLimit } from "./_services/action";
1313
import toast from "react-hot-toast";
14+
import FirstPostPrompt from "./_components/FirstPostPrompt";
15+
import { PlusCircle } from "lucide-react";
1416

1517
type SortField = "title" | "date" | "upvotes";
1618
type SortOrder = "asc" | "desc";
@@ -22,6 +24,7 @@ export default function FeedsPage() {
2224
const [debouncedQuery, setDebouncedQuery] = useState("");
2325
const [sortField, setSortField] = useState<SortField>("date");
2426
const [sortOrder, setSortOrder] = useState<SortOrder>("desc");
27+
const [userHasNotPostedYet, setUserHasNotPostedYet] = useState(false);
2528
const { user } = useUserStore();
2629

2730
useEffect(() => {
@@ -33,6 +36,21 @@ export default function FeedsPage() {
3336
if (user) fetchRole();
3437
}, [user]);
3538

39+
useEffect(() => {
40+
if (!user) return;
41+
42+
const checkIfUserHasPosted = async () => {
43+
try {
44+
const result = await hasNotPostedYet(user.id);
45+
setUserHasNotPostedYet(result);
46+
} catch (error) {
47+
console.error(error);
48+
}
49+
};
50+
51+
checkIfUserHasPosted();
52+
}, [user]);
53+
3654
useEffect(() => {
3755
const handler = setTimeout(
3856
() => setDebouncedQuery(searchQuery),
@@ -72,9 +90,21 @@ export default function FeedsPage() {
7290

7391
<SocialPointsCard />
7492

75-
<Button className="mb-4 mt-4 w-auto" onClick={openModal}>
76-
Create Post
77-
</Button>
93+
{userHasNotPostedYet && (
94+
<div className="mb-4">
95+
<FirstPostPrompt onCreatePost={openModal}/>
96+
</div>
97+
)}
98+
99+
{!userHasNotPostedYet && (
100+
<Button
101+
onClick={openModal}
102+
className="gap-2 w-auto mb-4"
103+
>
104+
<PlusCircle className="h-5 w-5" />
105+
Create Post
106+
</Button>
107+
)}
78108

79109
{/* Search bar + sort button row */}
80110
<div className="relative mb-6 flex items-center gap-4">

0 commit comments

Comments
 (0)