Skip to content

Commit 76a7b7d

Browse files
committed
Better product/community delete cleanup; bug fixes;
1 parent 277dfd1 commit 76a7b7d

20 files changed

Lines changed: 401 additions & 241 deletions

File tree

apps/docs/src/pages/en/communities/grant-access-to-additional-products.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ layout: ../../../layouts/MainLayout.astro
1818
2. Will the included product's email sequences be triggered?
1919
Yes, the included product's email sequences will be triggered.
2020

21-
![User edit screen](/assets/communities/member-permissions.png)
21+
3. Can I add unpublished products to the additional products?
22+
No, only published and visible products can be added as additional products. Additionally, only published products will be added to the user's account upon joining the community.

apps/web/app/(with-contexts)/(with-layout)/checkout/product.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export default function ProductCheckout() {
8888
emiAmount
8989
emiTotalInstallments
9090
subscriptionMonthlyAmount
91-
subscriptionYearlyAmont
91+
subscriptionYearlyAmount
9292
description
9393
includedProducts
9494
}

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

Lines changed: 111 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
TOAST_TITLE_SUCCESS,
1818
} from "@ui-config/strings";
1919
import { ChangeEvent, useContext, useEffect, useState } from "react";
20-
import { FetchBuilder } from "@courselit/utils";
2120
import {
2221
PaymentPlan,
2322
Constants,
@@ -58,7 +57,7 @@ import {
5857
DialogHeader,
5958
DialogTitle,
6059
} from "@/components/ui/dialog";
61-
import { Edit, FlagTriangleRight, Users, X } from "lucide-react";
60+
import { Edit, FlagTriangleRight, Loader2, Users, X } from "lucide-react";
6261
import {
6362
Select,
6463
SelectContent,
@@ -69,8 +68,10 @@ import {
6968
import PaymentPlanList from "@components/admin/payments/payment-plan-list";
7069
import { useCommunity } from "@/hooks/use-community";
7170
import { Button } from "@components/ui/button";
71+
import { Input } from "@/components/ui/input";
7272
import { redirect, useRouter } from "next/navigation";
7373
import { useMembership } from "@/hooks/use-membership";
74+
import { useGraphQLFetch } from "@/hooks/use-graphql-fetch";
7475
const { PaymentPlanType: paymentPlanType, MembershipEntityType } = Constants;
7576

7677
export default function Page({
@@ -112,7 +113,10 @@ export default function Page({
112113
const { community, error, loaded: communityLoaded } = useCommunity(id);
113114
const { membership, loaded: membershipLoaded } = useMembership(id);
114115
const [defaultPaymentPlan, setDefaultPaymentPlan] = useState("");
116+
const [deleteConfirmation, setDeleteConfirmation] = useState("");
117+
const [isDeleting, setIsDeleting] = useState(false);
115118
const router = useRouter();
119+
const fetch = useGraphQLFetch()
116120

117121
useEffect(() => {
118122
if (communityLoaded && community) {
@@ -133,11 +137,8 @@ export default function Page({
133137
}
134138
}, [community, communityLoaded, membership, membershipLoaded]);
135139

136-
const fetcher = new FetchBuilder()
137-
.setUrl(`${address.backend}/api/graph`)
138-
.setIsGraphQLEndpoint(true);
139-
140140
const handleDeleteConfirm = async () => {
141+
setIsDeleting(true);
141142
const query = `
142143
mutation DeleteCommunity($id: String!) {
143144
community: deleteCommunity(id: $id) {
@@ -146,7 +147,7 @@ export default function Page({
146147
}
147148
`;
148149

149-
const fetchRequest = fetcher
150+
const fetchRequest = fetch
150151
.setPayload({
151152
query,
152153
variables: {
@@ -170,6 +171,8 @@ export default function Page({
170171
description: error.message,
171172
variant: "destructive",
172173
});
174+
} finally {
175+
setIsDeleting(false);
173176
}
174177
};
175178

@@ -246,7 +249,7 @@ export default function Page({
246249
}
247250
}
248251
`;
249-
const fetchRequest = fetcher
252+
const fetchRequest = fetch
250253
.setPayload({
251254
query,
252255
variables: {
@@ -325,8 +328,7 @@ export default function Page({
325328
}
326329
`;
327330
try {
328-
const fetchRequest = new FetchBuilder()
329-
.setUrl(`${address.backend}/api/graph`)
331+
const fetchRequest = fetch
330332
.setPayload({
331333
query,
332334
variables: {
@@ -366,8 +368,7 @@ export default function Page({
366368
}
367369
`;
368370
try {
369-
const fetchRequest = new FetchBuilder()
370-
.setUrl(`${address.backend}/api/graph`)
371+
const fetchRequest = fetch
371372
.setPayload({
372373
query,
373374
variables: {
@@ -396,7 +397,7 @@ export default function Page({
396397
}
397398
};
398399

399-
const handleDeleteCategory = (category: Category) => {
400+
const handleDeleteCategory = (category: string) => {
400401
setDeletingCategory(category);
401402
setMigrationCategory("");
402403
};
@@ -411,8 +412,7 @@ export default function Page({
411412
}
412413
`;
413414
try {
414-
const fetchRequest = new FetchBuilder()
415-
.setUrl(`${address.backend}/api/graph`)
415+
const fetchRequest = fetch
416416
.setPayload({
417417
query,
418418
variables: {
@@ -443,74 +443,73 @@ export default function Page({
443443
}
444444
};
445445

446-
const onPlanSubmitted = async (plan: PaymentPlan) => {
447-
const query = `
448-
mutation CreatePlan(
449-
$name: String!,
450-
$type: PaymentPlanType!,
451-
$entityId: String!,
452-
$entityType: MembershipEntityType!
453-
$oneTimeAmount: Int,
454-
$emiAmount: Int,
455-
$emiTotalInstallments: Int,
456-
$subscriptionMonthlyAmount: Int,
457-
$subscriptionYearlyAmount: Int,
458-
) {
459-
plan: createPlan(
460-
name: $name,
461-
type: $type,
462-
entityId: $entityId,
463-
entityType: $entityType,
464-
oneTimeAmount: $oneTimeAmount,
465-
emiAmount: $emiAmount,
466-
emiTotalInstallments: $emiTotalInstallments,
467-
subscriptionMonthlyAmount: $subscriptionMonthlyAmount,
468-
subscriptionYearlyAmount: $subscriptionYearlyAmount,
469-
) {
470-
planId
471-
name
472-
type
473-
oneTimeAmount
474-
emiAmount
475-
emiTotalInstallments
476-
subscriptionMonthlyAmount
477-
subscriptionYearlyAmount
478-
}
479-
}
480-
`;
481-
try {
482-
const fetchRequest = new FetchBuilder()
483-
.setUrl(`${address.backend}/api/graph`)
484-
.setPayload({
485-
query,
486-
variables: {
487-
name: plan.name,
488-
type: plan.type,
489-
entityId: id,
490-
entityType:
491-
MembershipEntityType.COMMUNITY.toUpperCase(),
492-
oneTimeAmount: plan.oneTimeAmount,
493-
emiAmount: plan.emiAmount,
494-
emiTotalInstallments: plan.emiTotalInstallments,
495-
subscriptionMonthlyAmount:
496-
plan.subscriptionMonthlyAmount,
497-
subscriptionYearlyAmount: plan.subscriptionYearlyAmount,
498-
},
499-
})
500-
.setIsGraphQLEndpoint(true)
501-
.build();
502-
const response = await fetchRequest.exec();
503-
if (response.plan) {
504-
setPaymentPlans([...paymentPlans, response.plan]);
505-
}
506-
} catch (error: any) {
507-
toast({
508-
title: TOAST_TITLE_ERROR,
509-
description: error.message,
510-
variant: "destructive",
511-
});
512-
}
513-
};
446+
// const onPlanSubmitted = async (plan: PaymentPlan) => {
447+
// const query = `
448+
// mutation CreatePlan(
449+
// $name: String!,
450+
// $type: PaymentPlanType!,
451+
// $entityId: String!,
452+
// $entityType: MembershipEntityType!
453+
// $oneTimeAmount: Int,
454+
// $emiAmount: Int,
455+
// $emiTotalInstallments: Int,
456+
// $subscriptionMonthlyAmount: Int,
457+
// $subscriptionYearlyAmount: Int,
458+
// ) {
459+
// plan: createPlan(
460+
// name: $name,
461+
// type: $type,
462+
// entityId: $entityId,
463+
// entityType: $entityType,
464+
// oneTimeAmount: $oneTimeAmount,
465+
// emiAmount: $emiAmount,
466+
// emiTotalInstallments: $emiTotalInstallments,
467+
// subscriptionMonthlyAmount: $subscriptionMonthlyAmount,
468+
// subscriptionYearlyAmount: $subscriptionYearlyAmount,
469+
// ) {
470+
// planId
471+
// name
472+
// type
473+
// oneTimeAmount
474+
// emiAmount
475+
// emiTotalInstallments
476+
// subscriptionMonthlyAmount
477+
// subscriptionYearlyAmount
478+
// }
479+
// }
480+
// `;
481+
// try {
482+
// const fetchRequest = fetch
483+
// .setPayload({
484+
// query,
485+
// variables: {
486+
// name: plan.name,
487+
// type: plan.type,
488+
// entityId: id,
489+
// entityType:
490+
// MembershipEntityType.COMMUNITY.toUpperCase(),
491+
// oneTimeAmount: plan.oneTimeAmount,
492+
// emiAmount: plan.emiAmount,
493+
// emiTotalInstallments: plan.emiTotalInstallments,
494+
// subscriptionMonthlyAmount:
495+
// plan.subscriptionMonthlyAmount,
496+
// subscriptionYearlyAmount: plan.subscriptionYearlyAmount,
497+
// },
498+
// })
499+
// .setIsGraphQLEndpoint(true)
500+
// .build();
501+
// const response = await fetchRequest.exec();
502+
// if (response.plan) {
503+
// setPaymentPlans([...paymentPlans, response.plan]);
504+
// }
505+
// } catch (error: any) {
506+
// toast({
507+
// title: TOAST_TITLE_ERROR,
508+
// description: error.message,
509+
// variant: "destructive",
510+
// });
511+
// }
512+
// };
514513

515514
const onPlanArchived = async (planId: string) => {
516515
const query = `
@@ -528,8 +527,7 @@ export default function Page({
528527
}
529528
`;
530529
try {
531-
const fetchRequest = new FetchBuilder()
532-
.setUrl(`${address.backend}/api/graph`)
530+
const fetchRequest = fetch
533531
.setPayload({
534532
query,
535533
variables: {
@@ -562,8 +560,7 @@ export default function Page({
562560
}
563561
`;
564562
try {
565-
const fetchRequest = new FetchBuilder()
566-
.setUrl(`${address.backend}/api/graph`)
563+
const fetchRequest = fetch
567564
.setPayload({
568565
query,
569566
variables: {
@@ -801,7 +798,7 @@ export default function Page({
801798
<h3 className="text-lg font-semibold text-destructive">
802799
{DANGER_ZONE_HEADER}
803800
</h3>
804-
<AlertDialog>
801+
<AlertDialog onOpenChange={(open) => !open && (setDeleteConfirmation(""), setIsDeleting(false))}>
805802
<AlertDialogTrigger asChild>
806803
<Button variant="destructive">Delete Community</Button>
807804
</AlertDialogTrigger>
@@ -815,10 +812,34 @@ export default function Page({
815812
will be permanently deleted.
816813
</AlertDialogDescription>
817814
</AlertDialogHeader>
815+
<div className="py-4">
816+
<Label htmlFor="delete-confirmation" className="text-sm font-medium">
817+
Type &quot;delete&quot; to confirm
818+
</Label>
819+
<Input
820+
id="delete-confirmation"
821+
type="text"
822+
placeholder="Type 'delete' to confirm"
823+
value={deleteConfirmation}
824+
onChange={(e) => setDeleteConfirmation(e.target.value)}
825+
className="mt-2"
826+
/>
827+
</div>
818828
<AlertDialogFooter>
819829
<AlertDialogCancel>Cancel</AlertDialogCancel>
820-
<AlertDialogAction onClick={handleDeleteConfirm}>
821-
Delete
830+
<AlertDialogAction
831+
onClick={handleDeleteConfirm}
832+
disabled={deleteConfirmation !== "delete" || isDeleting}
833+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50 disabled:cursor-not-allowed"
834+
>
835+
{isDeleting ? (
836+
<>
837+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
838+
Deleting...
839+
</>
840+
) : (
841+
"Delete"
842+
)}
822843
</AlertDialogAction>
823844
</AlertDialogFooter>
824845
</AlertDialogContent>

apps/web/app/(with-contexts)/dashboard/(sidebar)/paymentplan/[type]/[id]/edit/[planid]/page.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useParams, useRouter } from "next/navigation";
44
import { useEffect } from "react";
5-
import { Constants, MembershipEntityType } from "@courselit/common-models";
5+
import { Constants } from "@courselit/common-models";
66
import DashboardContent from "@/components/admin/dashboard-content";
77
import {
88
PaymentPlanForm,
@@ -26,8 +26,10 @@ const {
2626
export default function EditPaymentPlanPage() {
2727
const params = useParams();
2828
const router = useRouter();
29-
30-
const entityType = params?.type as MembershipEntityType;
29+
const type = params?.type as "community" | "product";
30+
const entityType = type === "community"
31+
? membershipEntityType.COMMUNITY
32+
: membershipEntityType.COURSE;
3133
const entityId = params?.id as string;
3234
const planId = params?.planid as string;
3335
const { product, community } = useEntityValidation(entityType, entityId);
@@ -38,11 +40,11 @@ export default function EditPaymentPlanPage() {
3840
entityType === membershipEntityType.COMMUNITY
3941
? truncate(community?.name || "...", 10)
4042
: truncate(product?.title || "...", 10),
41-
href: `/dashboard/${entityType}/${entityId}`,
43+
href: `/dashboard/${type}/${entityId}`,
4244
},
4345
{
4446
label: COMMUNITY_SETTINGS,
45-
href: `/dashboard/${entityType === membershipEntityType.COMMUNITY ? "community" : "product"}/${entityId}/manage`,
47+
href: `/dashboard/${type}/${entityId}/manage`,
4648
},
4749
{ label: EDIT_PAYMENT_PLAN_HEADER, href: "#" },
4850
];

0 commit comments

Comments
 (0)