Skip to content

Commit

Permalink
Reporting content and almost all of end-to-end community experience
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajat Saxena committed Jan 5, 2025
1 parent f894ea7 commit ab868db
Show file tree
Hide file tree
Showing 113 changed files with 5,566 additions and 1,523 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added .yarn/cache/fsevents-patch-7934e3c202-8.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
74 changes: 15 additions & 59 deletions apps/web/app/(with-contexts)/(with-layout)/checkout/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
"use client";

import {
AddressContext,
ProfileContext,
SiteInfoContext,
} from "@components/contexts";
import { AddressContext } from "@components/contexts";
import Checkout, { Product } from "@components/public/payments/checkout";
import { Constants, PaymentPlan } from "@courselit/common-models";
import { useToast } from "@courselit/components-library";
Expand All @@ -15,52 +11,8 @@ import { useCallback, useContext, useEffect, useState } from "react";

const { MembershipEntityType } = Constants;

const product = {
id: "prod_001",
name: "Advanced AI Toolkit",
slug: "advanced-ai-toolkit",
featuredImage: "/placeholder.svg?height=400&width=400",
description: "Professional License",
};

const paymentPlans = [
{
id: "1",
name: "Basic Free",
type: "free",
},
{
id: "2",
name: "One-time Purchase",
type: "one-time",
oneTimeAmount: 299.99,
},
{
id: "3",
name: "Monthly Subscription",
type: "subscription",
subscriptionMonthlyAmount: 29.99,
},
{
id: "4",
name: "Yearly Subscription",
type: "subscription",
subscriptionMonthlyAmount: 24.99,
subscriptionYearlyAmount: 299.88,
},
{
id: "5",
name: "Flexible Payment",
type: "emi",
emiAmount: 59.99,
emiTotalInstallments: 6,
},
] as const;

export default function CheckoutPage() {
const address = useContext(AddressContext);
const siteinfo = useContext(SiteInfoContext);
const { profile } = useContext(ProfileContext);
const searchParams = useSearchParams();
const entityId = searchParams?.get("id");
const entityType = searchParams?.get("type");
Expand Down Expand Up @@ -126,20 +78,22 @@ export default function CheckoutPage() {

const getCommunity = useCallback(async () => {
const query = `
query ($id: String) {
query ($id: String!) {
community: getCommunity(id: $id) {
communityId,
name,
communityId
name
paymentPlans {
planId,
name,
type,
oneTimeAmount,
emiAmount,
emiTotalInstallments,
subscriptionMonthlyAmount,
planId
name
type
oneTimeAmount
emiAmount
emiTotalInstallments
subscriptionMonthlyAmount
subscriptionYearlyAmount
}
autoAcceptMembers
joiningReasonText
}
}
`;
Expand All @@ -155,6 +109,8 @@ export default function CheckoutPage() {
id: response.community.communityId,
name: response.community.name,
type: MembershipEntityType.COMMUNITY,
joiningReasonText: response.community.joiningReasonText,
autoAcceptMembers: response.community.autoAcceptMembers,
});
setPaymentPlans([...response.community.paymentPlans]);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"use client";

import { CheckCircle } from "lucide-react";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { PaymentVerificationStatus } from "./payment-verification-status";
import { useSearchParams } from "next/navigation";
import { useContext, useEffect, useState } from "react";
import { AddressContext } from "@components/contexts";
import { FetchBuilder } from "@courselit/utils";
import { InvoicesStatus } from "@courselit/common-models";

export default function Page() {
const params = useSearchParams();
const id = params?.get("id");
const [paymentStatus, setPaymentStatus] =
useState<InvoicesStatus>("pending");
const [loading, setLoading] = useState(false);
const address = useContext(AddressContext);

const verifyPayment = async () => {
setPaymentStatus("pending"); // Hide check status again
const fetch = new FetchBuilder()
.setUrl(`${address.backend}/api/payment/verify-new`)
.setHeaders({
"Content-Type": "application/json",
})
.setPayload(JSON.stringify({ id }))
.build();

try {
setLoading(true);
const response = await fetch.exec();
if (response.status) {
setPaymentStatus(response.status);
}
} catch (error) {
} finally {
setLoading(false);
}
};

useEffect(() => {
verifyPayment();
}, []);

return (
<div className="flex flex-col items-center justify-center space-y-6 text-center max-w-md mx-auto pt-20">
{paymentStatus === "paid" ? (
<>
{/* <CheckCircle className="w-16 h-16 text-green-500" /> */}
<h2 className="text-2xl font-bold">
Thank you for your purchase!
</h2>
<p className="text-muted-foreground">
Your order number is:{" "}
<span className="font-medium">{id}</span>
</p>
<CheckCircle className="w-8 h-8 text-green-500" />
<p className="text-lg font-medium text-green-600">
Payment verified successfully!
</p>
<p className="text-muted-foreground">
We have sent a confirmation email with order details and
tracking information.
</p>
</>
) : (
<>
<h2 className="text-2xl font-bold">
Thank you for your order!
</h2>
<p className="text-muted-foreground">
Your order number is:{" "}
<span className="font-medium">{id}</span>
</p>
<PaymentVerificationStatus
status={paymentStatus}
onRetryVerification={verifyPayment}
loading={loading}
/>
</>
)}

<div className="flex space-x-4 mt-6">
{paymentStatus === "paid" && (
<Button asChild>
<Link href="/dashboard4/my-content">
Go to Dashboard
</Link>
</Button>
)}
{/* <Button variant="outline" asChild>
<Link href="/support">Need Help?</Link>
</Button> */}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { XCircle, Loader2, RefreshCw, Clock } from "lucide-react";
import { Button } from "@/components/ui/button";
import { InvoicesStatus } from "@courselit/common-models";

interface PaymentVerificationStatusProps {
status: InvoicesStatus;
onRetryVerification: () => Promise<void>;
loading: boolean;
}

export function PaymentVerificationStatus({
status,
onRetryVerification,
loading,
}: PaymentVerificationStatusProps) {
return (
<div className="flex flex-col items-center space-y-4">
{status !== "paid" && (
<>
{status === "pending" && (
<>
<Button
onClick={onRetryVerification}
disabled={loading}
>
<>
<RefreshCw className="w-4 h-4 mr-2" />
Check status again
</>
</Button>
{!loading && (
<>
<Clock className="w-8 h-8 text-black-500" />
<p className="text-lg font-medium">
Payment not received yet
</p>
</>
)}
{loading && (
<>
<Loader2 className="w-16 h-16 text-blue-500 animate-spin" />
<h2 className="text-2xl font-bold">
Verifying payment...
</h2>
<p className="text-muted-foreground">
This may take a few moments
</p>
</>
)}
</>
)}
{status === "failed" && (
<>
<XCircle className="w-8 h-8 text-red-500" />
<p className="text-lg font-medium">
Payment verification failed
</p>
</>
)}
</>
)}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import { useState } from "react";
import { useCommunities } from "@/components/hooks/use-communities";
import { SkeletonCard } from "./skeleton-card";
import { ContentCard } from "./content-card";
import { PaginationControls } from "@components/public/pagination";
import { ContentItem } from "./types";

const ITEMS_PER_PAGE = 6;

export function CommunitiesList() {
const [currentPage, setCurrentPage] = useState(1);
const { communities, loading, totalPages } = useCommunities(
currentPage,
ITEMS_PER_PAGE,
);

return (
<div className="space-y-8">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{loading
? Array.from({ length: ITEMS_PER_PAGE }).map((_, index) => (
<SkeletonCard key={index} />
))
: communities.map((community: ContentItem) => (
<ContentCard
key={community.communityId}
community={community}
/>
))}
</div>
<PaginationControls
currentPage={currentPage}
totalPages={totalPages}
onPageChange={setCurrentPage}
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Image from "next/image";
import { Card, CardContent } from "@/components/ui/card";
import { Users } from "lucide-react";
import { Community } from "@courselit/common-models";
import { Link } from "@courselit/components-library";

export function ContentCard({ community }: { community: Community }) {
return (
<Link href={`/p/${community.pageId}`}>
<Card className="overflow-hidden transition-all duration-300 hover:shadow-lg hover:-translate-y-1">
<div className="relative aspect-video">
<Image
src={
community.featuredImage?.thumbnail ||
"/courselit_backdrop_square.webp"
}
alt={community.name}
fill
className="object-cover"
priority
/>
</div>
<CardContent className="p-4">
<h3 className="text-xl font-semibold mb-3">
{community.name}
</h3>
{community.membersCount && (
<div className="flex items-center text-sm text-muted-foreground">
<Users className="h-4 w-4 mr-2" />
<span>
{community.membersCount.toLocaleString()}{" "}
members
</span>
</div>
)}
</CardContent>
</Card>
</Link>
);
}
13 changes: 13 additions & 0 deletions apps/web/app/(with-contexts)/(with-layout)/communities/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Suspense } from "react";
import { CommunitiesList } from "./communities-list";

export default function CommunitiesPage() {
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-8">Communities</h1>
<Suspense fallback={<div>Loading...</div>}>
<CommunitiesList />
</Suspense>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Card, CardContent } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

export function SkeletonCard() {
return (
<Card className="overflow-hidden transition-all duration-300 hover:shadow-lg hover:-translate-y-1">
<Skeleton className="h-48 w-full" />
<CardContent className="p-4">
<Skeleton className="h-6 w-3/4 mb-4" />
<Skeleton className="h-4 w-1/2" />
</CardContent>
</Card>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default function HomepageLayout({
},
}}
>
{children}
<div className="mx-auto lg:max-w-[1200px] w-full">{children}</div>
</MasterLayout>
);
}
Loading

0 comments on commit ab868db

Please sign in to comment.