Skip to content

Commit 8108321

Browse files
author
Rajat Saxena
committed
WIP: payment plans without payment method added
1 parent aea149e commit 8108321

File tree

19 files changed

+185
-452
lines changed

19 files changed

+185
-452
lines changed

apps/web/app/(with-contexts)/dashboard4/(sidebar)/community/[id]/manage/page.tsx

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import PaymentPlanList from "@components/admin/payments/payment-plan-list";
7171
import { MembershipEntityType } from "@courselit/common-models/dist/constants";
7272
import { useCommunity } from "@components/hooks/useCommunity";
7373
import { Button } from "@components/ui/button";
74+
import { redirect } from "next/navigation";
7475
const { PaymentPlanType: paymentPlanType } = Constants;
7576

7677
export default function Page({
@@ -109,22 +110,57 @@ export default function Page({
109110
const [paymentPlans, setPaymentPlans] = useState<PaymentPlan[]>([]);
110111
const [featuredImage, setFeaturedImage] = useState<Media | null>(null);
111112
const { toast } = useToast();
112-
const { community, error } = useCommunity(id);
113+
const { community, error, loaded: communityLoaded } = useCommunity(id);
113114
const [defaultPaymentPlan, setDefaultPaymentPlan] = useState("");
114115

115116
useEffect(() => {
116-
if (community) {
117+
if (communityLoaded && community) {
117118
setCommunity(community);
118119
}
119-
}, [community]);
120+
if (communityLoaded && community === null) {
121+
redirect(`/dashboard4/community/${id}`);
122+
}
123+
}, [community, communityLoaded]);
124+
125+
const fetcher = new FetchBuilder()
126+
.setUrl(`${address.backend}/api/graph`)
127+
.setIsGraphQLEndpoint(true);
128+
129+
const handleDeleteConfirm = async () => {
130+
const query = `
131+
mutation DeleteCommunity($id: String!) {
132+
community: deleteCommunity(id: $id) {
133+
communityId
134+
}
135+
}
136+
`;
137+
138+
const fetchRequest = fetcher
139+
.setPayload({
140+
query,
141+
variables: {
142+
id,
143+
},
144+
})
145+
.build();
120146

121-
const handleDeleteConfirm = () => {
122-
toast({
123-
title: "Community Deleted",
124-
description:
125-
"Your community and all associated data have been permanently deleted.",
126-
variant: "destructive",
127-
});
147+
try {
148+
const response = await fetchRequest.exec();
149+
if (response.community) {
150+
toast({
151+
title: "Community Deleted",
152+
description:
153+
"Your community and all associated data have been permanently deleted.",
154+
variant: "destructive",
155+
});
156+
}
157+
} catch (error) {
158+
toast({
159+
title: TOAST_TITLE_ERROR,
160+
description: error.message,
161+
variant: "destructive",
162+
});
163+
}
128164
};
129165

130166
const setCommunity = (community: any) => {
@@ -198,22 +234,20 @@ export default function Page({
198234
}
199235
}
200236
`;
237+
const fetchRequest = fetcher
238+
.setPayload({
239+
query,
240+
variables: {
241+
id,
242+
name,
243+
description: JSON.stringify(description),
244+
enabled,
245+
autoAcceptMembers,
246+
joiningReasonText,
247+
},
248+
})
249+
.build();
201250
try {
202-
const fetchRequest = new FetchBuilder()
203-
.setUrl(`${address.backend}/api/graph`)
204-
.setPayload({
205-
query,
206-
variables: {
207-
id,
208-
name,
209-
description: JSON.stringify(description),
210-
enabled,
211-
autoAcceptMembers,
212-
joiningReasonText,
213-
},
214-
})
215-
.setIsGraphQLEndpoint(true)
216-
.build();
217251
const response = await fetchRequest.exec();
218252
if (response.community) {
219253
setCommunity(response.community);
@@ -763,6 +797,7 @@ export default function Page({
763797
}
764798
onDefaultPlanChanged={onDefaultPlanChanged}
765799
defaultPaymentPlanId={defaultPaymentPlan}
800+
paymentMethod={siteinfo.paymentMethod}
766801
/>
767802
</div>
768803
<Separator className="my-8" />

apps/web/app/api/payment/initiate-new/route.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ export async function POST(req: NextRequest) {
7878
const siteinfo = domain.settings;
7979
const paymentMethod = await getPaymentMethodFromSettings(siteinfo);
8080

81+
if (
82+
!paymentMethod &&
83+
paymentPlan.type !== Constants.PaymentPlanType.FREE
84+
) {
85+
return Response.json(
86+
{
87+
status: transactionFailed,
88+
error: responses.payment_invalid_settings,
89+
},
90+
{ status: 500 },
91+
);
92+
}
93+
8194
const existingMembership =
8295
await MembershipModel.findOne<InternalMembership>({
8396
domain: domain._id,
@@ -111,7 +124,7 @@ export async function POST(req: NextRequest) {
111124
paymentPlan.type === Constants.PaymentPlanType.SUBSCRIPTION)
112125
) {
113126
if (
114-
await paymentMethod.validateSubscription(
127+
await paymentMethod?.validateSubscription(
115128
membership.subscriptionId,
116129
)
117130
) {
@@ -159,7 +172,7 @@ export async function POST(req: NextRequest) {
159172
currencyISOCode: siteinfo.currencyISOCode,
160173
};
161174

162-
const paymentTracker = await paymentMethod.initiate({
175+
const paymentTracker = await paymentMethod!.initiate({
163176
metadata,
164177
paymentPlan,
165178
product: {
@@ -185,7 +198,7 @@ export async function POST(req: NextRequest) {
185198
paymentPlan.emiAmount ||
186199
0,
187200
status: Constants.InvoiceStatus.PENDING,
188-
paymentProcessor: paymentMethod.name,
201+
paymentProcessor: paymentMethod!.name,
189202
paymentProcessorEntityId: paymentTracker,
190203
currencyISOCode: siteinfo.currencyISOCode,
191204
});
@@ -235,6 +248,7 @@ async function getEntity(
235248
return await CommunityModel.findOne<Community>({
236249
communityId: id,
237250
domain: domainId,
251+
deleted: false,
238252
});
239253
} else if (type === Constants.MembershipEntityType.COURSE) {
240254
return await CourseModel.findOne<Course>({

apps/web/components/admin/payments/payment-plan-list.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
PaymentPlanType,
4343
Constants,
4444
PaymentPlan,
45+
PaymentMethod,
4546
} from "@courselit/common-models";
4647
import { capitalize } from "@courselit/utils";
4748
const { PaymentPlanType: paymentPlanType } = Constants;
@@ -197,6 +198,7 @@ export default function PaymentPlanList({
197198
currencyISOCode = "USD",
198199
onDefaultPlanChanged,
199200
defaultPaymentPlanId,
201+
paymentMethod,
200202
}: {
201203
paymentPlans: PaymentPlan[];
202204
onPlanSubmit: (values: z.infer<typeof formSchema>) => void;
@@ -206,6 +208,7 @@ export default function PaymentPlanList({
206208
currencyISOCode?: string;
207209
onDefaultPlanChanged?: (planId: string) => void;
208210
defaultPaymentPlanId?: string;
211+
paymentMethod?: PaymentMethod;
209212
}) {
210213
const [isFormVisible, setIsFormVisible] = useState(false);
211214
const [planType, setPlanType] = useState<PaymentPlanType>(
@@ -484,6 +487,9 @@ export default function PaymentPlanList({
484487
value={
485488
paymentPlanType.EMI
486489
}
490+
disabled={
491+
!paymentMethod
492+
}
487493
>
488494
EMI
489495
</SelectItem>
@@ -495,6 +501,9 @@ export default function PaymentPlanList({
495501
value={
496502
paymentPlanType.SUBSCRIPTION
497503
}
504+
disabled={
505+
!paymentMethod
506+
}
498507
>
499508
Subscription
500509
</SelectItem>
@@ -506,6 +515,9 @@ export default function PaymentPlanList({
506515
value={
507516
paymentPlanType.ONE_TIME
508517
}
518+
disabled={
519+
!paymentMethod
520+
}
509521
>
510522
One-time
511523
</SelectItem>

apps/web/components/admin/settings/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
MEDIA_SELECTOR_UPLOAD_BTN_CAPTION,
4141
MEDIA_SELECTOR_REMOVE_BTN_CAPTION,
4242
TOAST_TITLE_ERROR,
43+
TOAST_TITLE_SUCCESS,
4344
} from "@/ui-config/strings";
4445
import { FetchBuilder, capitalize } from "@courselit/utils";
4546
import { decode, encode } from "base-64";
@@ -440,6 +441,10 @@ const Settings = (props: SettingsProps) => {
440441
props.dispatch(
441442
setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)),
442443
);
444+
toast({
445+
title: TOAST_TITLE_SUCCESS,
446+
description: APP_MESSAGE_SETTINGS_SAVED,
447+
});
443448
}
444449
} catch (e: any) {
445450
props.dispatch(setAppMessage(new AppMessage(e.message)));
@@ -537,9 +542,18 @@ const Settings = (props: SettingsProps) => {
537542
props.dispatch(
538543
setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)),
539544
);
545+
toast({
546+
title: TOAST_TITLE_SUCCESS,
547+
description: APP_MESSAGE_SETTINGS_SAVED,
548+
});
540549
}
541550
} catch (e: any) {
542551
props.dispatch(setAppMessage(new AppMessage(e.message)));
552+
toast({
553+
title: TOAST_TITLE_ERROR,
554+
description: e.message,
555+
variant: "destructive",
556+
});
543557
} finally {
544558
props.dispatch(networkAction(false));
545559
}

apps/web/components/community/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,14 @@ export function CommunityForum({
13931393
</DropdownMenuContent>
13941394
</DropdownMenu>
13951395
</div>
1396-
<p>{post.content}</p>
1396+
<div>
1397+
<p className="text-base mb-4 font-semibold line-clamp-3">
1398+
{post.title}
1399+
</p>
1400+
<p className="text-sm mb-4 line-clamp-3">
1401+
{post.content}
1402+
</p>
1403+
</div>
13971404
{post.media && (
13981405
<div className="flex gap-2 overflow-x-auto">
13991406
{post.media.map(

apps/web/components/public/checkout-new-notused/free.tsx

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)