From e082fafe41e886a48364052ebc27fa962ed71d1b Mon Sep 17 00:00:00 2001 From: Ravi Rajput <121918062+ravirajput10@users.noreply.github.com> Date: Sat, 1 Feb 2025 20:37:12 +0530 Subject: [PATCH] Replaced old toast messages with the new (#531) * Replaced old toast messages with the new * Distinction between success and error toasts --------- Co-authored-by: Rajat Saxena --- .../dashboard4/(sidebar)/blog/[id]/page.tsx | 3 + .../dashboard4/(sidebar)/my-content/page2.tsx | 10 +- .../dashboard4/(sidebar)/profile/page.tsx | 30 +- .../dashboard4/(sidebar)/users/[id]/page.tsx | 50 ++- .../(sidebar)/users/tags/new/page.tsx | 14 +- .../dashboard4/(sidebar)/users/users-hub.tsx | 10 +- .../(with-contexts)/layout-with-context.tsx | 12 +- .../app/dashboard2/blog/[id]/blog-layout.tsx | 46 --- .../app/dashboard2/blog/[id]/details/page.tsx | 20 -- apps/web/app/dashboard2/blog/[id]/layout.tsx | 25 -- .../app/dashboard2/blog/[id]/publish/page.tsx | 12 - apps/web/app/dashboard2/blog/layout.tsx | 23 -- apps/web/app/dashboard2/blog/new/page.tsx | 13 - apps/web/app/dashboard2/blogs/layout.tsx | 18 - apps/web/app/dashboard2/blogs/page.tsx | 37 -- apps/web/app/dashboard2/help/layout.tsx | 16 - apps/web/app/dashboard2/help/page.tsx | 99 ------ apps/web/app/dashboard2/layout.tsx | 101 ------ .../mails/broadcast/[id]/edit/page.tsx | 24 -- apps/web/app/dashboard2/mails/mail-hub.tsx | 32 -- apps/web/app/dashboard2/mails/page.tsx | 23 -- .../sequence/[id]/[mailId]/edit/page.tsx | 26 -- .../mails/sequence/[id]/edit/page.tsx | 24 -- apps/web/app/dashboard2/my-content/layout.tsx | 16 - apps/web/app/dashboard2/my-content/page.tsx | 100 ------ apps/web/app/dashboard2/overview/layout.tsx | 16 - apps/web/app/dashboard2/overview/page.tsx | 70 ---- apps/web/app/dashboard2/page.tsx | 6 - apps/web/app/dashboard2/pages/layout.tsx | 18 - apps/web/app/dashboard2/pages/page.tsx | 27 -- .../dashboard2/product/[id]/content/page.tsx | 12 - .../product/[id]/customer/new/page.tsx | 18 - .../dashboard2/product/[id]/details/page.tsx | 20 -- .../app/dashboard2/product/[id]/layout.tsx | 25 -- .../dashboard2/product/[id]/pricing/page.tsx | 19 -- .../product/[id]/product-layout.tsx | 26 -- .../dashboard2/product/[id]/publish/page.tsx | 12 - .../dashboard2/product/[id]/reports/page.tsx | 12 - .../[section]/lesson/[lesson]/page.tsx | 26 -- .../section/[section]/lesson/new/page.tsx | 26 -- .../product/[id]/section/new/page.tsx | 18 - apps/web/app/dashboard2/product/layout.tsx | 29 -- apps/web/app/dashboard2/product/new/page.tsx | 17 - apps/web/app/dashboard2/products/layout.tsx | 18 - apps/web/app/dashboard2/products/page.tsx | 37 -- apps/web/app/dashboard2/profile/layout.tsx | 16 - apps/web/app/dashboard2/profile/page.tsx | 318 ------------------ apps/web/app/dashboard2/settings/layout.tsx | 18 - apps/web/app/dashboard2/settings/page.tsx | 41 --- apps/web/app/dashboard2/users/[id]/layout.tsx | 16 - apps/web/app/dashboard2/users/[id]/page.tsx | 234 ------------- apps/web/app/dashboard2/users/page.tsx | 23 -- .../app/dashboard2/users/tags/new/layout.tsx | 16 - .../app/dashboard2/users/tags/new/page.tsx | 11 - apps/web/app/dashboard2/users/tags/page.tsx | 11 - apps/web/app/dashboard2/users/users-hub.tsx | 264 --------------- apps/web/components/admin/blogs/blog-item.tsx | 10 +- .../admin/blogs/editor/course-hook.ts | 17 +- .../components/admin/blogs/editor/details.tsx | 39 ++- .../admin/blogs/editor/layout/header.tsx | 3 + .../components/admin/blogs/editor/publish.tsx | 17 +- apps/web/components/admin/blogs/helpers.ts | 31 +- apps/web/components/admin/blogs/index.tsx | 34 +- apps/web/components/admin/blogs/new-blog.tsx | 16 +- .../admin/mails/broadcast-editor.tsx | 55 ++- apps/web/components/admin/mails/index.tsx | 36 +- .../components/admin/mails/request-form.tsx | 37 +- .../admin/mails/sequence-editor-2.tsx | 41 ++- .../admin/mails/sequence-editor.tsx | 51 ++- .../admin/mails/sequence-mail-editor.tsx | 23 +- .../components/admin/mails/sequences-list.tsx | 21 +- .../admin/my-content/content-card.tsx | 4 +- .../components/admin/page-editor/index.tsx | 39 ++- apps/web/components/admin/pages/index.tsx | 34 +- apps/web/components/admin/pages/new-page.tsx | 13 +- .../admin/products/editor/content/lesson.tsx | 57 +++- .../products/editor/content/lessons-list.tsx | 30 +- .../admin/products/editor/course-hook.ts | 17 +- .../admin/products/editor/details.tsx | 39 ++- .../admin/products/editor/pricing.tsx | 33 +- .../admin/products/editor/publish.tsx | 13 +- .../admin/products/editor/section.tsx | 19 +- apps/web/components/admin/products/index.tsx | 12 +- .../admin/products/new-customer.tsx | 16 +- .../components/admin/products/new-product.tsx | 16 +- .../web/components/admin/products/product.tsx | 25 +- .../components/admin/settings/apikey/new.tsx | 27 +- apps/web/components/admin/settings/index.tsx | 57 ++-- apps/web/components/admin/users/details.tsx | 24 +- .../filter-editor/product.tsx | 13 +- .../filter-container/filter-editor/tagged.tsx | 13 +- .../users/filter-container/filter-save.tsx | 18 +- .../admin/users/filter-container/index.tsx | 19 +- .../users/filter-container/segment-editor.tsx | 18 +- apps/web/components/admin/users/index.tsx | 12 +- .../admin/users/permissions-editor.tsx | 20 +- .../web/components/admin/users/tags/index.tsx | 19 +- apps/web/components/admin/users/tags/new.tsx | 13 +- apps/web/components/app-toast.tsx | 66 ---- .../public/base-layout/template/index.tsx | 7 +- apps/web/components/public/checkout/free.tsx | 23 +- .../components/public/checkout/razorpay.tsx | 30 +- .../web/components/public/checkout/stripe.tsx | 25 +- .../components/public/lesson-viewer/index.tsx | 15 +- .../public/lesson-viewer/quiz-viewer.tsx | 36 +- .../web/components/public/purchase-status.tsx | 14 +- apps/web/components/public/scaffold.tsx | 7 +- apps/web/pages/dashboard/page/[id]/edit.tsx | 6 +- apps/web/pages/login.tsx | 23 +- apps/web/pages/profile/index.tsx | 35 +- apps/web/ui-config/strings.ts | 3 +- apps/web/ui-models/app-message.ts | 32 -- packages/common-models/src/app-message.ts | 32 -- packages/common-models/src/index.ts | 1 - packages/common-widgets/src/banner/widget.tsx | 15 +- .../common-widgets/src/content/widget.tsx | 22 +- .../common-widgets/src/email-form/widget.tsx | 35 +- .../state-management/src/action-creators.ts | 11 - 118 files changed, 982 insertions(+), 2711 deletions(-) delete mode 100644 apps/web/app/dashboard2/blog/[id]/blog-layout.tsx delete mode 100644 apps/web/app/dashboard2/blog/[id]/details/page.tsx delete mode 100644 apps/web/app/dashboard2/blog/[id]/layout.tsx delete mode 100644 apps/web/app/dashboard2/blog/[id]/publish/page.tsx delete mode 100644 apps/web/app/dashboard2/blog/layout.tsx delete mode 100644 apps/web/app/dashboard2/blog/new/page.tsx delete mode 100644 apps/web/app/dashboard2/blogs/layout.tsx delete mode 100644 apps/web/app/dashboard2/blogs/page.tsx delete mode 100644 apps/web/app/dashboard2/help/layout.tsx delete mode 100644 apps/web/app/dashboard2/help/page.tsx delete mode 100644 apps/web/app/dashboard2/layout.tsx delete mode 100644 apps/web/app/dashboard2/mails/broadcast/[id]/edit/page.tsx delete mode 100644 apps/web/app/dashboard2/mails/mail-hub.tsx delete mode 100644 apps/web/app/dashboard2/mails/page.tsx delete mode 100644 apps/web/app/dashboard2/mails/sequence/[id]/[mailId]/edit/page.tsx delete mode 100644 apps/web/app/dashboard2/mails/sequence/[id]/edit/page.tsx delete mode 100644 apps/web/app/dashboard2/my-content/layout.tsx delete mode 100644 apps/web/app/dashboard2/my-content/page.tsx delete mode 100644 apps/web/app/dashboard2/overview/layout.tsx delete mode 100644 apps/web/app/dashboard2/overview/page.tsx delete mode 100644 apps/web/app/dashboard2/page.tsx delete mode 100644 apps/web/app/dashboard2/pages/layout.tsx delete mode 100644 apps/web/app/dashboard2/pages/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/content/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/customer/new/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/details/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/layout.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/pricing/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/product-layout.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/publish/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/reports/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/section/[section]/lesson/[lesson]/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/section/[section]/lesson/new/page.tsx delete mode 100644 apps/web/app/dashboard2/product/[id]/section/new/page.tsx delete mode 100644 apps/web/app/dashboard2/product/layout.tsx delete mode 100644 apps/web/app/dashboard2/product/new/page.tsx delete mode 100644 apps/web/app/dashboard2/products/layout.tsx delete mode 100644 apps/web/app/dashboard2/products/page.tsx delete mode 100644 apps/web/app/dashboard2/profile/layout.tsx delete mode 100644 apps/web/app/dashboard2/profile/page.tsx delete mode 100644 apps/web/app/dashboard2/settings/layout.tsx delete mode 100644 apps/web/app/dashboard2/settings/page.tsx delete mode 100644 apps/web/app/dashboard2/users/[id]/layout.tsx delete mode 100644 apps/web/app/dashboard2/users/[id]/page.tsx delete mode 100644 apps/web/app/dashboard2/users/page.tsx delete mode 100644 apps/web/app/dashboard2/users/tags/new/layout.tsx delete mode 100644 apps/web/app/dashboard2/users/tags/new/page.tsx delete mode 100644 apps/web/app/dashboard2/users/tags/page.tsx delete mode 100644 apps/web/app/dashboard2/users/users-hub.tsx delete mode 100644 apps/web/components/app-toast.tsx delete mode 100644 apps/web/ui-models/app-message.ts delete mode 100644 packages/common-models/src/app-message.ts diff --git a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/blog/[id]/page.tsx b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/blog/[id]/page.tsx index 2f8cd7000..c00a301cc 100644 --- a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/blog/[id]/page.tsx +++ b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/blog/[id]/page.tsx @@ -12,6 +12,7 @@ import { MenuItem, Skeleton, Tabbs, + useToast, } from "@courselit/components-library"; import { MoreVert } from "@courselit/icons"; import { @@ -41,6 +42,7 @@ export default function Page({ params }: { params: { id: string } }) { const { profile } = useContext(ProfileContext); const course = useCourse(id, address); const router = useRouter(); + const { toast } = useToast(); return ( @@ -83,6 +85,7 @@ export default function Page({ params }: { params: { id: string } }) { `/dashboard4/blogs`, ); }, + toast, }) } > diff --git a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/my-content/page2.tsx b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/my-content/page2.tsx index 6f1a0fc9f..4b7f3fcd3 100644 --- a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/my-content/page2.tsx +++ b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/my-content/page2.tsx @@ -7,11 +7,13 @@ import { Link, Section, Skeleton, + useToast, } from "@courselit/components-library"; import { FetchBuilder } from "@courselit/utils"; import { ACCOUNT_NO_PURCHASE_PLACEHOLDER, ACCOUNT_PROGRESS_SUFFIX, + TOAST_TITLE_ERROR, MY_CONTENT_HEADER, VISIT_COURSE_BUTTON, } from "@ui-config/strings"; @@ -22,6 +24,7 @@ const breadcrumbs = [{ label: MY_CONTENT_HEADER, href: "#" }]; export default function Page() { const [courses, setCourses] = useState([]); const [loaded, setLoaded] = useState(false); + const { toast } = useToast(); const { profile } = useContext(ProfileContext); const address = useContext(AddressContext); @@ -50,7 +53,12 @@ export default function Page() { setCourses(response.courses); } setLoaded(true); - } catch (e: any) {} + } catch (e: any) { + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + }); + } }; loadEnrolledCourses(); diff --git a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/profile/page.tsx b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/profile/page.tsx index 2e4166b55..4076c0e9e 100644 --- a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/profile/page.tsx +++ b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/profile/page.tsx @@ -15,10 +15,12 @@ import { MediaSelector, PageBuilderPropertyHeader, Section, + useToast, } from "@courselit/components-library"; import { FetchBuilder } from "@courselit/utils"; import { BUTTON_SAVE, + TOAST_TITLE_ERROR, MEDIA_SELECTOR_REMOVE_BTN_CAPTION, MEDIA_SELECTOR_UPLOAD_BTN_CAPTION, PROFILE_EMAIL_PREFERENCES, @@ -41,6 +43,7 @@ export default function Page() { useState>(); const [avatar, setAvatar] = useState>({}); const [subscribedToUpdates, setSubscribedToUpdates] = useState(false); + const { toast } = useToast(); const { profile, setProfile } = useContext(ProfileContext); const address = useContext(AddressContext); @@ -83,7 +86,11 @@ export default function Page() { setSubscribedToUpdates(response.user.subscribedToUpdates); } } catch (err: any) { - console.error(`Profile page: ${err.message}`); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }; if (profile.userId && address.backend) { @@ -140,8 +147,11 @@ export default function Page() { setProfile(response.user); } } catch (err: any) { - console.error(err); - } finally { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }; @@ -198,8 +208,11 @@ export default function Page() { setProfile(response.user); } } catch (err: any) { - console.error(err); - } finally { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }; @@ -231,8 +244,11 @@ export default function Page() { await fetch.exec(); } catch (err: any) { setSubscribedToUpdates(!state); - console.error(err); - } finally { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }; diff --git a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/[id]/page.tsx b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/[id]/page.tsx index f6f6b7e3f..94757b88e 100644 --- a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/[id]/page.tsx +++ b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/[id]/page.tsx @@ -4,9 +4,16 @@ import DashboardContent from "@components/admin/dashboard-content"; import { PermissionsEditor } from "@components/admin/users/permissions-editor"; import { AddressContext } from "@components/contexts"; import { UserWithAdminFields } from "@courselit/common-models"; -import { ComboBox, Link, Section, Switch } from "@courselit/components-library"; +import { + ComboBox, + Link, + Section, + Switch, + useToast, +} from "@courselit/components-library"; import { FetchBuilder } from "@courselit/utils"; import { + TOAST_TITLE_ERROR, PAGE_HEADER_ALL_USER, PAGE_HEADER_EDIT_USER, SWITCH_ACCOUNT_ACTIVE, @@ -28,6 +35,7 @@ export default function Page({ params }: { params: { id: string } }) { const [tags, setTags] = useState([]); const address = useContext(AddressContext); const { id } = params; + const { toast } = useToast(); useEffect(() => { getUserDetails(); @@ -49,7 +57,13 @@ export default function Page({ params }: { params: { id: string } }) { if (response.tags) { setTags(response.tags); } - } catch (err) {} + } catch (err) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); + } }, [address.backend]); useEffect(() => { @@ -86,7 +100,13 @@ export default function Page({ params }: { params: { id: string } }) { if (response.user) { setUserData(response.user); } - } catch (err: any) {} + } catch (err: any) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); + } }; // TODO: test this method. A hard-coded userId was there in the query. @@ -107,7 +127,13 @@ export default function Page({ params }: { params: { id: string } }) { try { const response = await fetch.exec(); setEnrolledCourses(response.enrolledCourses); - } catch (err) {} + } catch (err) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); + } }; const toggleActiveState = async (value: boolean) => { @@ -137,7 +163,13 @@ export default function Page({ params }: { params: { id: string } }) { if (response.user) { setUserData(response.user); } - } catch (err: any) {} + } catch (err: any) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); + } }; const updateTags = async (tags: string[]) => { @@ -173,7 +205,13 @@ export default function Page({ params }: { params: { id: string } }) { if (response.user) { setUserData(response.user); } - } catch (err: any) {} + } catch (err: any) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); + } }; if (!userData) { diff --git a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/tags/new/page.tsx b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/tags/new/page.tsx index 57c3cb1f0..a2f1196f3 100644 --- a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/tags/new/page.tsx +++ b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/tags/new/page.tsx @@ -1,11 +1,17 @@ "use client"; import React, { useState, ChangeEvent, useContext } from "react"; -import { Button, Form, FormField } from "@courselit/components-library"; +import { + Button, + Form, + FormField, + useToast, +} from "@courselit/components-library"; import { BTN_CONTINUE, BTN_NEW_TAG, BUTTON_CANCEL_TEXT, + TOAST_TITLE_ERROR, USERS_MANAGER_PAGE_HEADING, USERS_TAG_HEADER, USERS_TAG_NEW_HEADER, @@ -41,6 +47,7 @@ export default function Page() { const [name, setName] = useState(""); const [loading, setLoading] = useState(false); const router = useRouter(); + const { toast } = useToast(); const { profile } = useContext(ProfileContext); const createTag = async (e: FormEvent) => { @@ -68,6 +75,11 @@ export default function Page() { router.replace("/dashboard4/users/tags"); } } catch (err: any) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { setLoading(false); } diff --git a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/users-hub.tsx b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/users-hub.tsx index f75f79eb4..3040b5b3d 100644 --- a/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/users-hub.tsx +++ b/apps/web/app/(with-contexts)/dashboard4/(sidebar)/users/users-hub.tsx @@ -19,9 +19,11 @@ import { TableBody, TableHead, TableRow, + useToast, } from "@courselit/components-library"; import { checkPermission, FetchBuilder } from "@courselit/utils"; import { + TOAST_TITLE_ERROR, USER_TABLE_HEADER_JOINED, USER_TABLE_HEADER_LAST_ACTIVE, USER_TABLE_HEADER_NAME, @@ -44,6 +46,7 @@ export default function UsersHub() { const [filtersAggregator, setFiltersAggregator] = useState("or"); const [count, setCount] = useState(0); + const { toast } = useToast(); const { profile } = useContext(ProfileContext); @@ -130,8 +133,11 @@ export default function UsersHub() { setCount(response.count); } } catch (err) { - console.error(err); - } finally { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }, [address.backend, page, rowsPerPage, filters, filtersAggregator]); diff --git a/apps/web/app/(with-contexts)/layout-with-context.tsx b/apps/web/app/(with-contexts)/layout-with-context.tsx index 1270f9747..981b16ee2 100644 --- a/apps/web/app/(with-contexts)/layout-with-context.tsx +++ b/apps/web/app/(with-contexts)/layout-with-context.tsx @@ -11,7 +11,8 @@ import { TypefacesContext, ServerConfigContext, } from "@components/contexts"; -import { Toaster } from "@courselit/components-library"; +import { Toaster, useToast } from "@courselit/components-library"; +import { TOAST_TITLE_ERROR } from "@ui-config/strings"; import { Session } from "next-auth"; export default function Layout({ @@ -30,6 +31,7 @@ export default function Layout({ session: Session | null; }) { const [profile, setProfile] = useState(defaultState.profile); + const { toast } = useToast(); useEffect(() => { const getUserProfile = async () => { @@ -69,7 +71,13 @@ export default function Layout({ if (response.profile) { setProfile(response.profile); } - } catch (e) {} + } catch (err) { + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); + } }; if (address && session) { diff --git a/apps/web/app/dashboard2/blog/[id]/blog-layout.tsx b/apps/web/app/dashboard2/blog/[id]/blog-layout.tsx deleted file mode 100644 index 46ccd97af..000000000 --- a/apps/web/app/dashboard2/blog/[id]/blog-layout.tsx +++ /dev/null @@ -1,46 +0,0 @@ -"use client"; - -import BlogEditorLayout from "@components/admin/blogs/editor/layout"; -import LoadingScreen from "@components/admin/loading-screen"; -import { - AddressContext, - ProfileContext, - SiteInfoContext, -} from "@components/contexts"; -import { Profile, UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { ReactNode, useContext } from "react"; -const { permissions } = UIConstants; - -export default function BlogLayout({ - id, - children, -}: { - id: string; - children: ReactNode; -}) { - const address = useContext(AddressContext); - const siteinfo = useContext(SiteInfoContext); - const { profile } = useContext(ProfileContext); - - if ( - !checkPermission(profile.permissions!, [ - permissions.manageAnyCourse, - permissions.manageCourse, - ]) - ) { - return ; - } - - return ( - - {children} - - ); -} diff --git a/apps/web/app/dashboard2/blog/[id]/details/page.tsx b/apps/web/app/dashboard2/blog/[id]/details/page.tsx deleted file mode 100644 index 309f89741..000000000 --- a/apps/web/app/dashboard2/blog/[id]/details/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -"use client"; - -import { Details } from "@components/admin/blogs/editor/details"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { Profile } from "@courselit/common-models"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const { id } = params; - - return ( -
- ); -} diff --git a/apps/web/app/dashboard2/blog/[id]/layout.tsx b/apps/web/app/dashboard2/blog/[id]/layout.tsx deleted file mode 100644 index 9d9d346d4..000000000 --- a/apps/web/app/dashboard2/blog/[id]/layout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { Metadata, ResolvingMetadata } from "next"; -import BlogLayout from "./blog-layout"; -import { ReactNode } from "react"; -import { EDIT_BLOG } from "@ui-config/strings"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${EDIT_BLOG} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ - params, - children, -}: { - params: { id: string }; - children: ReactNode; -}) { - const { id } = params; - - return {children}; -} diff --git a/apps/web/app/dashboard2/blog/[id]/publish/page.tsx b/apps/web/app/dashboard2/blog/[id]/publish/page.tsx deleted file mode 100644 index ecc9b46d1..000000000 --- a/apps/web/app/dashboard2/blog/[id]/publish/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -"use client"; - -import { Publish } from "@components/admin/blogs/editor/publish"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const { id } = params; - - return ; -} diff --git a/apps/web/app/dashboard2/blog/layout.tsx b/apps/web/app/dashboard2/blog/layout.tsx deleted file mode 100644 index 19970aa32..000000000 --- a/apps/web/app/dashboard2/blog/layout.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; - -import LoadingScreen from "@components/admin/loading-screen"; -import { ProfileContext } from "@components/contexts"; -import { UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { ReactNode, useContext } from "react"; -const { permissions } = UIConstants; - -export default function Page({ children }: { children: ReactNode }) { - const { profile } = useContext(ProfileContext); - - if ( - !checkPermission(profile.permissions!, [ - permissions.manageAnyCourse, - permissions.manageCourse, - ]) - ) { - return ; - } - - return children; -} diff --git a/apps/web/app/dashboard2/blog/new/page.tsx b/apps/web/app/dashboard2/blog/new/page.tsx deleted file mode 100644 index 15a54b502..000000000 --- a/apps/web/app/dashboard2/blog/new/page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -"use client"; - -import { NewBlog } from "@components/admin/blogs/new-blog"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page() { - const address = useContext(AddressContext); - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/blogs/layout.tsx b/apps/web/app/dashboard2/blogs/layout.tsx deleted file mode 100644 index 1950d2e27..000000000 --- a/apps/web/app/dashboard2/blogs/layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { MANAGE_BLOG_PAGE_HEADING } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${MANAGE_BLOG_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/blogs/page.tsx b/apps/web/app/dashboard2/blogs/page.tsx deleted file mode 100644 index 62e51a01a..000000000 --- a/apps/web/app/dashboard2/blogs/page.tsx +++ /dev/null @@ -1,37 +0,0 @@ -"use client"; - -import { Index as Blogs } from "@components/admin/blogs"; -import LoadingScreen from "@components/admin/loading-screen"; -import { - AddressContext, - ProfileContext, - SiteInfoContext, -} from "@components/contexts"; -import { UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { useContext } from "react"; -const { permissions } = UIConstants; - -export default function Page() { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const siteinfo = useContext(SiteInfoContext); - - if ( - !checkPermission(profile.permissions!, [ - permissions.manageAnyCourse, - permissions.manageCourse, - ]) - ) { - return ; - } - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/help/layout.tsx b/apps/web/app/dashboard2/help/layout.tsx deleted file mode 100644 index eccc5f8b3..000000000 --- a/apps/web/app/dashboard2/help/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { HELP_HEADER } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${HELP_HEADER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/help/page.tsx b/apps/web/app/dashboard2/help/page.tsx deleted file mode 100644 index 90dab19c6..000000000 --- a/apps/web/app/dashboard2/help/page.tsx +++ /dev/null @@ -1,99 +0,0 @@ -"use client"; - -import { - Button2, - Card, - CardContent, - CardFooter, - CardHeader, - CardTitle, -} from "@courselit/components-library"; -import { HELP_HEADER } from "@ui-config/strings"; - -export default function Page() { - return ( -
-
-

{HELP_HEADER}

-
-

- If you need a helping hand, we are out there for you. -

-
- - - Documentation - - -

- Our documentation contains tutorials to do - everything in CourseLit. -

-
- - - - See documentation - - - -
- - - Ask in Discord - - -

- Come ask your questions directly from the team. We - are quite active there. -

-
- - - Open Discord - - -
- - - Found a bug? - - -

- We encourage you to raise an issue so that we can - make the product better for everyone. -

-
- - - Post an issue - - -
-
-
-

- Priority Support -

-

- In case you need to get in touch with the team to get help - faster, we offer paid support. Please reach - out to us on{" "} - - CourseLit Support - {" "} - with your requirements . -

-
-
- ); -} diff --git a/apps/web/app/dashboard2/layout.tsx b/apps/web/app/dashboard2/layout.tsx deleted file mode 100644 index a0ab248ab..000000000 --- a/apps/web/app/dashboard2/layout.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { ReactNode } from "react"; -import { auth } from "@/auth"; -import Layout from "@components/layout"; -import { FetchBuilder } from "@courselit/utils"; -import { headers } from "next/headers"; -import { getBackendAddress } from "@ui-lib/utils"; -import { defaultState } from "@components/default-state"; -import { decode } from "base-64"; -import { SiteInfo } from "@courselit/common-models"; -import { redirect } from "next/navigation"; -import "../../styles/globals.css"; - -interface PageProps { - children: ReactNode; -} - -export default async function Page({ children }: PageProps) { - const session = await auth(); - if (!session) { - redirect("/login"); - } - const headersList = headers(); - const address = getBackendAddress({ - "x-forwarded-proto": headersList.get("x-forwarded-proto"), - host: headersList.get("host"), - }); - - const siteInfoQuery = ` - { site: getSiteInfo { - name, - settings { - title, - subtitle, - logo { - file, - caption - }, - currencyISOCode, - paymentMethod, - stripeKey, - codeInjectionHead, - codeInjectionBody, - mailingAddress, - hideCourseLitBranding, - razorpayKey, - }, - theme { - name, - active, - styles, - url - }, - typefaces { - section, - typeface, - fontWeights - }, - } - } - `; - const siteInfoFetch = new FetchBuilder() - .setUrl(`${address}/api/graph`) - .setPayload(siteInfoQuery) - .setIsGraphQLEndpoint(true) - .build(); - const siteInfoResponse = await siteInfoFetch.exec(); - let finalSiteInfo: SiteInfo = {}; - if (siteInfoResponse.site.settings) { - const siteinfo = siteInfoResponse.site.settings; - finalSiteInfo = { - title: siteinfo.title || defaultState.siteinfo.title, - subtitle: siteinfo.subtitle || defaultState.siteinfo.subtitle, - logo: siteinfo.logo || defaultState.siteinfo.logo, - currencyISOCode: - siteinfo.currencyISOCode || - defaultState.siteinfo.currencyISOCode, - paymentMethod: - siteinfo.paymentMethod || defaultState.siteinfo.paymentMethod, - stripeKey: siteinfo.stripeKey || defaultState.siteinfo.stripeKey, - codeInjectionHead: - decode(siteinfo.codeInjectionHead) || - defaultState.siteinfo.codeInjectionHead, - codeInjectionBody: - decode(siteinfo.codeInjectionBody) || - defaultState.siteinfo.codeInjectionBody, - mailingAddress: - siteinfo.mailingAddress || defaultState.siteinfo.mailingAddress, - hideCourseLitBranding: - siteinfo.hideCourseLitBranding || - defaultState.siteinfo.hideCourseLitBranding, - razorpayKey: - siteinfo.razorpayKey || defaultState.siteinfo.razorpayKey, - }; - } - - return ( - -
{children}
-
- ); -} diff --git a/apps/web/app/dashboard2/mails/broadcast/[id]/edit/page.tsx b/apps/web/app/dashboard2/mails/broadcast/[id]/edit/page.tsx deleted file mode 100644 index fce005b08..000000000 --- a/apps/web/app/dashboard2/mails/broadcast/[id]/edit/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client"; - -import BroadcastEditor from "@components/admin/mails/broadcast-editor"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ - params, -}: { - params: { - id: string; - }; -}) { - const address = useContext(AddressContext); - const { id } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/mails/mail-hub.tsx b/apps/web/app/dashboard2/mails/mail-hub.tsx deleted file mode 100644 index 798d97c83..000000000 --- a/apps/web/app/dashboard2/mails/mail-hub.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client"; - -import Mails from "@components/admin/mails"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { checkPermission } from "@courselit/utils"; -import { useSearchParams } from "next/navigation"; -import { useContext } from "react"; -import { UIConstants } from "@courselit/common-models"; -import LoadingScreen from "@components/admin/loading-screen"; - -const { permissions } = UIConstants; - -export default function MailHub() { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const searchParams = useSearchParams(); - - const tab = searchParams?.get("tab") || "Broadcasts"; - - if (!checkPermission(profile.permissions!, [permissions.manageSite])) { - return ; - } - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/mails/page.tsx b/apps/web/app/dashboard2/mails/page.tsx deleted file mode 100644 index 3223a9acc..000000000 --- a/apps/web/app/dashboard2/mails/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Metadata, ResolvingMetadata } from "next"; -import MailHub from "./mail-hub"; - -export async function generateMetadata( - { - params, - searchParams, - }: { - params: any; - searchParams: { [key: string]: string | string[] | undefined }; - }, - parent: ResolvingMetadata, -): Promise { - const tab = searchParams["tab"] || "Broadcasts"; - - return { - title: `${tab} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Page() { - return ; -} diff --git a/apps/web/app/dashboard2/mails/sequence/[id]/[mailId]/edit/page.tsx b/apps/web/app/dashboard2/mails/sequence/[id]/[mailId]/edit/page.tsx deleted file mode 100644 index e89d2b02a..000000000 --- a/apps/web/app/dashboard2/mails/sequence/[id]/[mailId]/edit/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; - -import SequenceMailEditor from "@components/admin/mails/sequence-mail-editor"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ - params, -}: { - params: { - id: string; - mailId: string; - }; -}) { - const address = useContext(AddressContext); - const { id, mailId } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/mails/sequence/[id]/edit/page.tsx b/apps/web/app/dashboard2/mails/sequence/[id]/edit/page.tsx deleted file mode 100644 index 9da651d12..000000000 --- a/apps/web/app/dashboard2/mails/sequence/[id]/edit/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client"; - -import SequenceEditor from "@components/admin/mails/sequence-editor"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ - params, -}: { - params: { - id: string; - }; -}) { - const address = useContext(AddressContext); - const { id } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/my-content/layout.tsx b/apps/web/app/dashboard2/my-content/layout.tsx deleted file mode 100644 index cbcf58bfd..000000000 --- a/apps/web/app/dashboard2/my-content/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { MY_CONTENT_HEADER } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${MY_CONTENT_HEADER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/my-content/page.tsx b/apps/web/app/dashboard2/my-content/page.tsx deleted file mode 100644 index 5e133c473..000000000 --- a/apps/web/app/dashboard2/my-content/page.tsx +++ /dev/null @@ -1,100 +0,0 @@ -"use client"; - -import { AddressContext, ProfileContext } from "@components/contexts"; -import { - Button2, - Link, - Section, - Skeleton, -} from "@courselit/components-library"; -import { FetchBuilder } from "@courselit/utils"; -import { - ACCOUNT_NO_PURCHASE_PLACEHOLDER, - ACCOUNT_PROGRESS_SUFFIX, - MY_CONTENT_HEADER, - VISIT_COURSE_BUTTON, -} from "@ui-config/strings"; -import { useContext, useEffect, useState } from "react"; - -export default function Page() { - const [courses, setCourses] = useState([]); - const [loaded, setLoaded] = useState(false); - - const { profile } = useContext(ProfileContext); - const address = useContext(AddressContext); - - useEffect(() => { - const loadEnrolledCourses = async () => { - const query = ` - query { - courses: getEnrolledCourses (userId: "${profile.userId}"){ - courseId, - title, - type, - slug, - progress - } - } - `; - try { - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(query) - .setIsGraphQLEndpoint(true) - .build(); - const response = await fetch.exec(); - if (response.courses) { - setCourses(response.courses); - } - setLoaded(true); - } catch (e: any) {} - }; - - loadEnrolledCourses(); - }, [address.backend, profile.userId]); - - return ( -
-

{MY_CONTENT_HEADER}

- {!loaded && ( -
- - -
- )} - {loaded && - courses.length > 0 && - courses.map((course: Record) => ( -
-
-
-

- {course.title} -

-

- {( - (course.progress as unknown) * 100 - ).toFixed(2)} - {ACCOUNT_PROGRESS_SUFFIX} -

-
-
-
- - {VISIT_COURSE_BUTTON} - -
-
-
-
- ))} - {loaded && !courses.length && ( -

- {ACCOUNT_NO_PURCHASE_PLACEHOLDER} -

- )} -
- ); -} diff --git a/apps/web/app/dashboard2/overview/layout.tsx b/apps/web/app/dashboard2/overview/layout.tsx deleted file mode 100644 index ff8aee492..000000000 --- a/apps/web/app/dashboard2/overview/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { OVERVIEW_HEADER } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${OVERVIEW_HEADER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/overview/page.tsx b/apps/web/app/dashboard2/overview/page.tsx deleted file mode 100644 index c0e3cd67e..000000000 --- a/apps/web/app/dashboard2/overview/page.tsx +++ /dev/null @@ -1,70 +0,0 @@ -"use client"; - -import { Metric } from "@components/admin/dashboard/metric"; -import { Todo } from "@components/admin/dashboard/to-do"; -import LoadingScreen from "@components/admin/loading-screen"; -import { - AddressContext, - ProfileContext, - SiteInfoContext, -} from "@components/contexts"; -import { UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { DASHBOARD_PAGE_HEADER } from "@ui-config/strings"; -import { useContext } from "react"; - -export default function Page() { - const siteInfo = useContext(SiteInfoContext); - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - - if ( - !checkPermission(profile.permissions!, [ - UIConstants.permissions.manageAnyCourse, - UIConstants.permissions.manageCourse, - UIConstants.permissions.manageMedia, - UIConstants.permissions.manageSettings, - UIConstants.permissions.manageSite, - UIConstants.permissions.manageUsers, - ]) - ) { - return ; - } - - return ( -
-

- {DASHBOARD_PAGE_HEADER} -

-
- -
-
- - - - -
-
- ); -} diff --git a/apps/web/app/dashboard2/page.tsx b/apps/web/app/dashboard2/page.tsx deleted file mode 100644 index 1c344844a..000000000 --- a/apps/web/app/dashboard2/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { redirect } from "next/navigation"; - -export default function Page() { - redirect("/dashboard2/my-content"); - return
; -} diff --git a/apps/web/app/dashboard2/pages/layout.tsx b/apps/web/app/dashboard2/pages/layout.tsx deleted file mode 100644 index ff4e72c99..000000000 --- a/apps/web/app/dashboard2/pages/layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { MANAGE_PAGES_PAGE_HEADING } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${MANAGE_PAGES_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/pages/page.tsx b/apps/web/app/dashboard2/pages/page.tsx deleted file mode 100644 index 4ed1ea2df..000000000 --- a/apps/web/app/dashboard2/pages/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -"use client"; - -import LoadingScreen from "@components/admin/loading-screen"; -import { Pages } from "@components/admin/pages"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { useContext } from "react"; -const { permissions } = UIConstants; - -export default function Page() { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - - if (!checkPermission(profile.permissions!, [permissions.manageSite])) { - return ; - } - - return ( - {}} - prefix="/dashboard2" - /> - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/content/page.tsx b/apps/web/app/dashboard2/product/[id]/content/page.tsx deleted file mode 100644 index ec089880f..000000000 --- a/apps/web/app/dashboard2/product/[id]/content/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -"use client"; - -import ContentEditor from "@components/admin/products/editor/content"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const { id } = params; - - return ; -} diff --git a/apps/web/app/dashboard2/product/[id]/customer/new/page.tsx b/apps/web/app/dashboard2/product/[id]/customer/new/page.tsx deleted file mode 100644 index 5372df0cf..000000000 --- a/apps/web/app/dashboard2/product/[id]/customer/new/page.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client"; - -import NewCustomer from "@components/admin/products/new-customer"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const { id } = params; - const address = useContext(AddressContext); - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/details/page.tsx b/apps/web/app/dashboard2/product/[id]/details/page.tsx deleted file mode 100644 index 305f48f5b..000000000 --- a/apps/web/app/dashboard2/product/[id]/details/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -"use client"; - -import DetailsEditor from "@components/admin/products/editor/details"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { Profile } from "@courselit/common-models"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const { id } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/layout.tsx b/apps/web/app/dashboard2/product/[id]/layout.tsx deleted file mode 100644 index e3c668f08..000000000 --- a/apps/web/app/dashboard2/product/[id]/layout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { Metadata, ResolvingMetadata } from "next"; -import ProductLayout from "./product-layout"; -import { ReactNode } from "react"; -import { EDIT_PRODUCT_HEADER } from "@ui-config/strings"; - -export async function generateMetadata( - { params }: { params: any }, - parent: ResolvingMetadata, -): Promise { - return { - title: `${EDIT_PRODUCT_HEADER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ - params, - children, -}: { - params: { id: string }; - children: ReactNode; -}) { - const { id } = params; - - return {children}; -} diff --git a/apps/web/app/dashboard2/product/[id]/pricing/page.tsx b/apps/web/app/dashboard2/product/[id]/pricing/page.tsx deleted file mode 100644 index c9afd561a..000000000 --- a/apps/web/app/dashboard2/product/[id]/pricing/page.tsx +++ /dev/null @@ -1,19 +0,0 @@ -"use client"; - -import PricingEditor from "@components/admin/products/editor/pricing"; -import { AddressContext, SiteInfoContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const siteinfo = useContext(SiteInfoContext); - const { id } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/product-layout.tsx b/apps/web/app/dashboard2/product/[id]/product-layout.tsx deleted file mode 100644 index e196b8f30..000000000 --- a/apps/web/app/dashboard2/product/[id]/product-layout.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; - -import ProductEditorLayout from "@components/admin/products/editor/layout"; -import { AddressContext } from "@components/contexts"; -import { usePathname } from "next/navigation"; -import { ReactNode, useContext } from "react"; - -export default function ProductLayout({ - id, - children, -}: { - id: string; - children: ReactNode; -}) { - const address = useContext(AddressContext); - const path = usePathname(); - const isNewCustomerAdditionScreen = path?.indexOf("/customer/new") !== -1; - - return isNewCustomerAdditionScreen ? ( - children - ) : ( - - {children} - - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/publish/page.tsx b/apps/web/app/dashboard2/product/[id]/publish/page.tsx deleted file mode 100644 index ce80fb04b..000000000 --- a/apps/web/app/dashboard2/product/[id]/publish/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -"use client"; - -import PublishingEditor from "@components/admin/products/editor/publish"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const { id } = params; - - return ; -} diff --git a/apps/web/app/dashboard2/product/[id]/reports/page.tsx b/apps/web/app/dashboard2/product/[id]/reports/page.tsx deleted file mode 100644 index 6c4f42322..000000000 --- a/apps/web/app/dashboard2/product/[id]/reports/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -"use client"; - -import CourseReports from "@components/admin/products/editor/reports"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const { id } = params; - const address = useContext(AddressContext); - - return ; -} diff --git a/apps/web/app/dashboard2/product/[id]/section/[section]/lesson/[lesson]/page.tsx b/apps/web/app/dashboard2/product/[id]/section/[section]/lesson/[lesson]/page.tsx deleted file mode 100644 index 6fc6d5888..000000000 --- a/apps/web/app/dashboard2/product/[id]/section/[section]/lesson/[lesson]/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; - -import LessonEditor from "@/components/admin/products/editor/content/lesson"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ - params, -}: { - params: { id: string; section: string; lesson: string }; -}) { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const { id, section, lesson } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/section/[section]/lesson/new/page.tsx b/apps/web/app/dashboard2/product/[id]/section/[section]/lesson/new/page.tsx deleted file mode 100644 index 87dda04ed..000000000 --- a/apps/web/app/dashboard2/product/[id]/section/[section]/lesson/new/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; - -import LessonEditor from "@/components/admin/products/editor/content/lesson"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ - params, -}: { - params: { id: string; section: string }; -}) { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const { id, section } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/product/[id]/section/new/page.tsx b/apps/web/app/dashboard2/product/[id]/section/new/page.tsx deleted file mode 100644 index c4680f4e7..000000000 --- a/apps/web/app/dashboard2/product/[id]/section/new/page.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client"; - -import SectionEditor from "@components/admin/products/editor/section"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const address = useContext(AddressContext); - const { id } = params; - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/product/layout.tsx b/apps/web/app/dashboard2/product/layout.tsx deleted file mode 100644 index 4af87fa67..000000000 --- a/apps/web/app/dashboard2/product/layout.tsx +++ /dev/null @@ -1,29 +0,0 @@ -"use client"; - -import LoadingScreen from "@components/admin/loading-screen"; -import { ProfileContext } from "@components/contexts"; -import { UIConstants } from "@courselit/common-models"; -import { Toaster } from "@courselit/components-library"; -import { checkPermission } from "@courselit/utils"; -import { ReactNode, useContext } from "react"; -const { permissions } = UIConstants; - -export default function Page({ children }: { children: ReactNode }) { - const { profile } = useContext(ProfileContext); - - if ( - !checkPermission(profile.permissions!, [ - permissions.manageAnyCourse, - permissions.manageCourse, - ]) - ) { - return ; - } - - return ( - <> - {children} - - - ); -} diff --git a/apps/web/app/dashboard2/product/new/page.tsx b/apps/web/app/dashboard2/product/new/page.tsx deleted file mode 100644 index 58fa42524..000000000 --- a/apps/web/app/dashboard2/product/new/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -"use client"; - -import { NewProduct } from "@components/admin/products/new-product"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page() { - const address = useContext(AddressContext); - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/products/layout.tsx b/apps/web/app/dashboard2/products/layout.tsx deleted file mode 100644 index daf605a15..000000000 --- a/apps/web/app/dashboard2/products/layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { MANAGE_COURSES_PAGE_HEADING } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${MANAGE_COURSES_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/products/page.tsx b/apps/web/app/dashboard2/products/page.tsx deleted file mode 100644 index 9816ce265..000000000 --- a/apps/web/app/dashboard2/products/page.tsx +++ /dev/null @@ -1,37 +0,0 @@ -"use client"; - -import LoadingScreen from "@components/admin/loading-screen"; -import { Index as Products } from "@components/admin/products"; -import { - AddressContext, - ProfileContext, - SiteInfoContext, -} from "@components/contexts"; -import { UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { useContext } from "react"; -const { permissions } = UIConstants; - -export default function Page() { - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const siteinfo = useContext(SiteInfoContext); - - if ( - !checkPermission(profile.permissions!, [ - permissions.manageAnyCourse, - permissions.manageCourse, - ]) - ) { - return ; - } - - return ( - - ); -} diff --git a/apps/web/app/dashboard2/profile/layout.tsx b/apps/web/app/dashboard2/profile/layout.tsx deleted file mode 100644 index 6ff8cf60a..000000000 --- a/apps/web/app/dashboard2/profile/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { PROFILE_PAGE_HEADER } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${PROFILE_PAGE_HEADER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/profile/page.tsx b/apps/web/app/dashboard2/profile/page.tsx deleted file mode 100644 index de8a2b8d5..000000000 --- a/apps/web/app/dashboard2/profile/page.tsx +++ /dev/null @@ -1,318 +0,0 @@ -"use client"; - -import { AddressContext, ProfileContext } from "@components/contexts"; -import { Media, Profile } from "@courselit/common-models"; -import { - Avatar, - AvatarFallback, - AvatarImage, - Button2, - Checkbox, - Form, - FormField, - Image, - MediaSelector, - PageBuilderPropertyHeader, - Section, -} from "@courselit/components-library"; -import { FetchBuilder } from "@courselit/utils"; -import { - BUTTON_SAVE, - MEDIA_SELECTOR_REMOVE_BTN_CAPTION, - MEDIA_SELECTOR_UPLOAD_BTN_CAPTION, - PROFILE_EMAIL_PREFERENCES, - PROFILE_EMAIL_PREFERENCES_NEWSLETTER_OPTION_TEXT, - PROFILE_PAGE_HEADER, - PROFILE_SECTION_DETAILS, - PROFILE_SECTION_DETAILS_BIO, - PROFILE_SECTION_DETAILS_EMAIL, - PROFILE_SECTION_DETAILS_NAME, - PROFILE_SECTION_DISPLAY_PICTURE, -} from "@ui-config/strings"; -import { FormEvent, useContext, useEffect, useState } from "react"; - -export default function Page() { - const [bio, setBio] = useState(""); - const [name, setName] = useState(""); - const [user, setUser] = - useState>(); - const [avatar, setAvatar] = useState>({}); - const [subscribedToUpdates, setSubscribedToUpdates] = useState(false); - - const { profile } = useContext(ProfileContext); - const address = useContext(AddressContext); - - useEffect(() => { - const getUser = async function (userId: string) { - const query = ` - query { - user: getUser(userId: "${userId}") { - name, - bio, - email, - subscribedToUpdates, - avatar { - mediaId, - originalFileName, - mimeType, - size, - access, - file, - thumbnail, - caption - }, - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(query) - .setIsGraphQLEndpoint(true) - .build(); - - try { - const response = await fetch.exec(); - if (response.user) { - setUser(response.user); - setName(response.user.name); - setBio(response.user.bio); - setAvatar(response.user.avatar); - setSubscribedToUpdates(response.user.subscribedToUpdates); - } - } catch (err: any) { - console.error(`Profile page: ${err.message}`); - } - }; - if (profile.userId && address.backend) { - getUser(profile.userId); - } - }, [profile, address.backend]); - - const updateProfilePic = async (media?: Media) => { - const mutation = ` - mutation ($id: ID!, $avatar: MediaInput) { - user: updateUser(userData: { - id: $id - avatar: $avatar - }) { - id, - name, - bio, - avatar { - mediaId, - originalFileName, - mimeType, - size, - access, - file, - thumbnail, - caption - }, - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload({ - query: mutation, - variables: { - id: profile.id, - avatar: media || null, - }, - }) - .setIsGraphQLEndpoint(true) - .build(); - - try { - await fetch.exec(); - } catch (err: any) { - console.error(err); - } finally { - } - }; - - const saveDetails = async (e: FormEvent) => { - e.preventDefault(); - - const mutation = ` - mutation ($id: ID!, $name: String, $bio: String) { - user: updateUser(userData: { - id: $id - name: $name - bio: $bio - }) { - id, - name, - bio, - avatar { - mediaId, - originalFileName, - mimeType, - size, - access, - file, - thumbnail, - caption - }, - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload({ - query: mutation, - variables: { - id: profile.id, - name, - bio, - }, - }) - .setIsGraphQLEndpoint(true) - .build(); - - try { - await fetch.exec(); - } catch (err: any) { - console.error(err); - } finally { - } - }; - - const saveEmailPreference = async function (state: boolean) { - setSubscribedToUpdates(state); - const mutation = ` - mutation ($id: ID!, $subscribedToUpdates: Boolean) { - user: updateUser(userData: { - id: $id - subscribedToUpdates: $subscribedToUpdates - }) { - subscribedToUpdates - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload({ - query: mutation, - variables: { - id: profile.id, - subscribedToUpdates: state, - }, - }) - .setIsGraphQLEndpoint(true) - .build(); - - try { - await fetch.exec(); - } catch (err: any) { - setSubscribedToUpdates(!state); - console.error(err); - } finally { - } - }; - - return ( -
-
-

- {PROFILE_PAGE_HEADER} -

-
-
- - - - - profile pic - - - { - if (media) { - updateProfilePic(media); - } - }} - onRemove={() => { - updateProfilePic(); - }} - access="public" - strings={{ - buttonCaption: - MEDIA_SELECTOR_UPLOAD_BTN_CAPTION, - removeButtonCaption: - MEDIA_SELECTOR_REMOVE_BTN_CAPTION, - }} - type="user" - hidePreview={true} - /> -
-
-
- {}} - disabled={true} - /> - - setName(event.target.value) - } - /> - setBio(event.target.value)} - label={PROFILE_SECTION_DETAILS_BIO} - multiline={true} - maxRows={5} - /> -
- - {BUTTON_SAVE} - -
-
-
-
-
-
-

- {PROFILE_EMAIL_PREFERENCES_NEWSLETTER_OPTION_TEXT} -

- - saveEmailPreference(value) - } - /> -
-
-
-
- ); -} diff --git a/apps/web/app/dashboard2/settings/layout.tsx b/apps/web/app/dashboard2/settings/layout.tsx deleted file mode 100644 index 2bbb4fc2f..000000000 --- a/apps/web/app/dashboard2/settings/layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { SITE_SETTINGS_PAGE_HEADING } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${SITE_SETTINGS_PAGE_HEADING} | ${ - (await parent)?.title?.absolute - }`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/settings/page.tsx b/apps/web/app/dashboard2/settings/page.tsx deleted file mode 100644 index 11af38fc9..000000000 --- a/apps/web/app/dashboard2/settings/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import LoadingScreen from "@components/admin/loading-screen"; -import Settings from "@components/admin/settings"; -import { - AddressContext, - ProfileContext, - SiteInfoContext, -} from "@components/contexts"; -import { Profile, UIConstants } from "@courselit/common-models"; -import { checkPermission } from "@courselit/utils"; -import { useSearchParams } from "next/navigation"; -import { useContext } from "react"; -const { permissions } = UIConstants; - -export default function Page() { - const siteinfo = useContext(SiteInfoContext); - const address = useContext(AddressContext); - const { profile } = useContext(ProfileContext); - const searchParams = useSearchParams(); - - const tab = searchParams?.get("tab") || "Branding"; - - if (!checkPermission(profile.permissions!, [permissions.manageSettings])) { - return ; - } - - return ( - {}} - loading={false} - networkAction={false} - prefix="/dashboard2" - /> - ); -} diff --git a/apps/web/app/dashboard2/users/[id]/layout.tsx b/apps/web/app/dashboard2/users/[id]/layout.tsx deleted file mode 100644 index b812fab6a..000000000 --- a/apps/web/app/dashboard2/users/[id]/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { PAGE_HEADER_EDIT_USER } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${PAGE_HEADER_EDIT_USER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/users/[id]/page.tsx b/apps/web/app/dashboard2/users/[id]/page.tsx deleted file mode 100644 index 2a5643a0c..000000000 --- a/apps/web/app/dashboard2/users/[id]/page.tsx +++ /dev/null @@ -1,234 +0,0 @@ -"use client"; - -import { PermissionsEditor } from "@components/admin/users/permissions-editor"; -import { AddressContext } from "@components/contexts"; -import { UserWithAdminFields } from "@courselit/common-models"; -import { - Breadcrumbs, - ComboBox, - Link, - Section, - Switch, -} from "@courselit/components-library"; -import { FetchBuilder } from "@courselit/utils"; -import { - PAGE_HEADER_EDIT_USER, - SWITCH_ACCOUNT_ACTIVE, - USER_BASIC_DETAILS_HEADER, - USER_EMAIL_SUBHEADER, - USER_NAME_SUBHEADER, - USER_TAGS_SUBHEADER, - USERS_MANAGER_PAGE_HEADING, -} from "@ui-config/strings"; -import { useCallback, useContext, useEffect, useState } from "react"; - -export default function Page({ params }: { params: { id: string } }) { - const [userData, setUserData] = useState(); - const [_, setEnrolledCourses] = useState([]); - const [tags, setTags] = useState([]); - const address = useContext(AddressContext); - const { id } = params; - - useEffect(() => { - getUserDetails(); - }, [id]); - - const getTags = useCallback(async () => { - const query = ` - query { - tags - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(query) - .setIsGraphQLEndpoint(true) - .build(); - try { - const response = await fetch.exec(); - if (response.tags) { - setTags(response.tags); - } - } catch (err) {} - }, [address.backend]); - - useEffect(() => { - if (userData) { - getEnrolledCourses(); - } - getTags(); - }, [getTags]); - - const getUserDetails = async () => { - const query = ` - query { - user: getUser(userId: "${id}") { - id, - email, - name, - active, - permissions, - userId, - purchases { - courseId - }, - tags - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(query) - .setIsGraphQLEndpoint(true) - .build(); - try { - const response = await fetch.exec(); - if (response.user) { - setUserData(response.user); - } - } catch (err: any) {} - }; - - // TODO: test this method. A hard-coded userId was there in the query. - const getEnrolledCourses = async () => { - const query = ` - query { - enrolledCourses: getEnrolledCourses(userId: "${userData!.id}") { - id, - title - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(query) - .setIsGraphQLEndpoint(true) - .build(); - try { - const response = await fetch.exec(); - setEnrolledCourses(response.enrolledCourses); - } catch (err) {} - }; - - const toggleActiveState = async (value: boolean) => { - const mutation = ` - mutation { - user: updateUser(userData: { - id: "${userData!.id}" - active: ${value} - }) { - id, - email, - name, - active, - permissions, - userId, - tags - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(mutation) - .setIsGraphQLEndpoint(true) - .build(); - try { - const response = await fetch.exec(); - if (response.user) { - setUserData(response.user); - } - } catch (err: any) {} - }; - - const updateTags = async (tags: string[]) => { - const mutation = ` - mutation UpdateTags($id: ID!, $tags: [String]!) { - user: updateUser(userData: { - id: $id, - tags: $tags - }) { - id, - email, - name, - active, - permissions, - userId, - tags - } - } - `; - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload({ - query: mutation, - variables: { - id: userData.id, - tags, - }, - }) - .setIsGraphQLEndpoint(true) - .build(); - try { - const response = await fetch.exec(); - if (response.user) { - setUserData(response.user); - } - } catch (err: any) {} - }; - - if (!userData) { - return null; - } - - return ( -
- - - {USERS_MANAGER_PAGE_HEADING} - - -

{PAGE_HEADER_EDIT_USER}

-
-

- {userData.name ? userData.name : userData.email} -

-
-
-
-

{USER_NAME_SUBHEADER}

-

{userData.name || "--"}

-
-
-

{USER_EMAIL_SUBHEADER}

-

- - {userData.email} - -

-
-
- {SWITCH_ACCOUNT_ACTIVE} - toggleActiveState(value)} - /> -
-
-

{USER_TAGS_SUBHEADER}

- -
-
- -
-
- ); -} diff --git a/apps/web/app/dashboard2/users/page.tsx b/apps/web/app/dashboard2/users/page.tsx deleted file mode 100644 index f92e54a50..000000000 --- a/apps/web/app/dashboard2/users/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Metadata, ResolvingMetadata } from "next"; -import UsersHub from "./users-hub"; - -export async function generateMetadata( - { - params, - searchParams, - }: { - params: any; - searchParams: { [key: string]: string | string[] | undefined }; - }, - parent: ResolvingMetadata, -): Promise { - const tab = searchParams["tab"] || "All users"; - - return { - title: `${tab} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Page() { - return ; -} diff --git a/apps/web/app/dashboard2/users/tags/new/layout.tsx b/apps/web/app/dashboard2/users/tags/new/layout.tsx deleted file mode 100644 index bfcc853a1..000000000 --- a/apps/web/app/dashboard2/users/tags/new/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { USERS_TAG_NEW_HEADER } from "@ui-config/strings"; -import type { Metadata, ResolvingMetadata } from "next"; -import { ReactNode } from "react"; - -export async function generateMetadata( - _: any, - parent: ResolvingMetadata, -): Promise { - return { - title: `${USERS_TAG_NEW_HEADER} | ${(await parent)?.title?.absolute}`, - }; -} - -export default function Layout({ children }: { children: ReactNode }) { - return children; -} diff --git a/apps/web/app/dashboard2/users/tags/new/page.tsx b/apps/web/app/dashboard2/users/tags/new/page.tsx deleted file mode 100644 index bb5b649fb..000000000 --- a/apps/web/app/dashboard2/users/tags/new/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -"use client"; - -import { NewTag } from "@components/admin/users/tags/new"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page() { - const address = useContext(AddressContext); - - return ; -} diff --git a/apps/web/app/dashboard2/users/tags/page.tsx b/apps/web/app/dashboard2/users/tags/page.tsx deleted file mode 100644 index c8e794352..000000000 --- a/apps/web/app/dashboard2/users/tags/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -"use client"; - -import Tags from "@components/admin/users/tags"; -import { AddressContext } from "@components/contexts"; -import { useContext } from "react"; - -export default function Page() { - const address = useContext(AddressContext); - - return ; -} diff --git a/apps/web/app/dashboard2/users/users-hub.tsx b/apps/web/app/dashboard2/users/users-hub.tsx deleted file mode 100644 index 2cdb4f8e7..000000000 --- a/apps/web/app/dashboard2/users/users-hub.tsx +++ /dev/null @@ -1,264 +0,0 @@ -"use client"; - -import LoadingScreen from "@components/admin/loading-screen"; -import FilterContainer from "@components/admin/users/filter-container"; -import Tags from "@components/admin/users/tags"; -import { AddressContext, ProfileContext } from "@components/contexts"; -import { - User, - UserFilter, - UIConstants, - UserFilterAggregator, -} from "@courselit/common-models"; -import { - Avatar, - AvatarFallback, - AvatarImage, - Button, - Link, - Table, - TableBody, - TableHead, - TableRow, - Tabbs, -} from "@courselit/components-library"; -import { checkPermission, FetchBuilder } from "@courselit/utils"; -import { - USER_TABLE_HEADER_JOINED, - USER_TABLE_HEADER_LAST_ACTIVE, - USER_TABLE_HEADER_NAME, - USERS_MANAGER_PAGE_HEADING, - USERS_TAG_NEW_HEADER, -} from "@ui-config/strings"; -import { formattedLocaleDate } from "@ui-lib/utils"; -import { useRouter, useSearchParams } from "next/navigation"; -import { useCallback, useContext, useEffect, useState } from "react"; - -const { permissions } = UIConstants; - -export default function UsersHub() { - const address = useContext(AddressContext); - const searchParams = useSearchParams(); - - const tab = searchParams?.get("tab") || "Users"; - - const [page, setPage] = useState(1); - const [rowsPerPage, _] = useState(10); - const [users, setUsers] = useState([]); - const [filters, setFilters] = useState([]); - const [filtersAggregator, setFiltersAggregator] = - useState("or"); - const [count, setCount] = useState(0); - const router = useRouter(); - - const { profile } = useContext(ProfileContext); - - const loadUsers = useCallback(async () => { - const query = - filters.length !== 0 - ? ` - query { - users: getUsers(searchData: { - filters: ${JSON.stringify( - JSON.stringify({ - aggregator: filtersAggregator, - filters, - }), - )} - offset: ${page}, - rowsPerPage: ${rowsPerPage} - }) { - name, - userId, - email, - permissions, - createdAt, - updatedAt - avatar { - mediaId, - originalFileName, - mimeType, - size, - access, - file, - thumbnail, - caption - }, - }, - count: getUsersCount(searchData: { - filters: ${JSON.stringify( - JSON.stringify({ - aggregator: filtersAggregator, - filters, - }), - )} - }) - } - ` - : ` - query { - users: getUsers(searchData: { - offset: ${page}, - rowsPerPage: ${rowsPerPage} - }) { - name, - userId, - email, - permissions, - createdAt, - updatedAt - avatar { - mediaId, - originalFileName, - mimeType, - size, - access, - file, - thumbnail, - caption - }, - }, - count: getUsersCount - } - `; - - const fetch = new FetchBuilder() - .setUrl(`${address.backend}/api/graph`) - .setPayload(query) - .setIsGraphQLEndpoint(true) - .build(); - try { - const response = await fetch.exec(); - if (response.users) { - setUsers(response.users); - } - if (typeof response.count !== "undefined") { - setCount(response.count); - } - } catch (err) { - console.error(err); - } finally { - } - }, [address.backend, page, rowsPerPage, filters, filtersAggregator]); - - useEffect(() => { - loadUsers(); - }, [loadUsers]); - - const onFilterChange = useCallback(({ filters, aggregator, segmentId }) => { - setFilters(filters); - setFiltersAggregator(aggregator); - setPage(1); - }, []); - - if (!checkPermission(profile.permissions!, [permissions.manageSite])) { - return ; - } - - return ( -
-
-

- {USERS_MANAGER_PAGE_HEADING} -

- {tab === "Tags" && ( -
- -
- )} -
- { - router.replace(`/dashboard2/users?tab=${tab}`); - }} - > -
-
- -
- - - - - - - - {users.map((user) => ( - - - - - - ))} - -
{USER_TABLE_HEADER_NAME}{USER_TABLE_HEADER_JOINED} - {USER_TABLE_HEADER_LAST_ACTIVE} - -
- - - - {(user.name - ? user.name.charAt(0) - : user.email.charAt(0) - ).toUpperCase()} - - -
- - - {user.name - ? user.name - : user.email} - - -
- {user.email} -
-
-
-
- {user.createdAt - ? formattedLocaleDate( - user.createdAt, - ) - : ""} - - {user.updatedAt !== user.createdAt - ? user.updatedAt - ? formattedLocaleDate( - user.updatedAt, - ) - : "" - : ""} -
-
- -
-
- ); -} diff --git a/apps/web/components/admin/blogs/blog-item.tsx b/apps/web/components/admin/blogs/blog-item.tsx index 5f01a98e5..6ea49c2eb 100644 --- a/apps/web/components/admin/blogs/blog-item.tsx +++ b/apps/web/components/admin/blogs/blog-item.tsx @@ -11,7 +11,13 @@ import { MoreVert } from "@courselit/icons"; import type { AppDispatch } from "@courselit/state-management"; import type { SiteInfo, Address } from "@courselit/common-models"; // import { connect } from "react-redux"; -import { Chip, Menu2, MenuItem, Link } from "@courselit/components-library"; +import { + Chip, + Menu2, + MenuItem, + Link, + useToast, +} from "@courselit/components-library"; import { deleteProduct } from "./helpers"; import { TableRow } from "@courselit/components-library"; @@ -34,6 +40,7 @@ export default function BlogItem({ prefix: string; }) { const product = details; + const { toast } = useToast(); return ( @@ -76,6 +83,7 @@ export default function BlogItem({ onDeleteComplete: () => { onDelete(position); }, + toast, }) } > diff --git a/apps/web/components/admin/blogs/editor/course-hook.ts b/apps/web/components/admin/blogs/editor/course-hook.ts index 3f8c75fc8..9c2b80e07 100644 --- a/apps/web/components/admin/blogs/editor/course-hook.ts +++ b/apps/web/components/admin/blogs/editor/course-hook.ts @@ -1,10 +1,9 @@ -import { Address, AppMessage, Course } from "@courselit/common-models"; +import { Address, Course } from "@courselit/common-models"; +import { useToast } from "@courselit/components-library"; import { AppDispatch /*AppState*/ } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; +import { TOAST_TITLE_ERROR } from "@ui-config/strings"; import { useCallback, useEffect, useState } from "react"; type CourseWithAdminProps = Partial< @@ -23,6 +22,7 @@ export default function useCourse( const [course, setCourse] = useState< CourseWithAdminProps | undefined | null >(); + const { toast } = useToast(); const loadCourse = useCallback( async (courseId: string) => { @@ -64,8 +64,11 @@ export default function useCourse( } } catch (err: any) { setCourse(null); - dispatch && - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/blogs/editor/details.tsx b/apps/web/components/admin/blogs/editor/details.tsx index 37afe754d..c5b562d5a 100644 --- a/apps/web/components/admin/blogs/editor/details.tsx +++ b/apps/web/components/admin/blogs/editor/details.tsx @@ -7,19 +7,19 @@ import { FormField, Button, PageBuilderPropertyHeader, + useToast, } from "@courselit/components-library"; import useCourse from "./course-hook"; import { FetchBuilder } from "@courselit/utils"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; -import { Address, AppMessage, Profile } from "@courselit/common-models"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; +import { Address, Profile } from "@courselit/common-models"; import { APP_MESSAGE_COURSE_SAVED, BUTTON_SAVE, COURSE_CONTENT_HEADER, + TOAST_TITLE_ERROR, FORM_FIELD_FEATURED_IMAGE, + TOAST_TITLE_SUCCESS, } from "../../../../ui-config/strings"; import { connect } from "react-redux"; import { AppDispatch, AppState } from "@courselit/state-management"; @@ -39,6 +39,7 @@ export function Details({ id, address, dispatch, profile }: DetailsProps) { const [featuredImage, setFeaturedImage] = useState>({}); const [refreshDetails, setRefreshDetails] = useState(0); const course = useCourse(id, address, dispatch); + const { toast } = useToast(); useEffect(() => { if (course) { @@ -76,13 +77,17 @@ export function Details({ id, address, dispatch, profile }: DetailsProps) { dispatch && dispatch(networkAction(true)); const response = await fetch.exec(); if (response.updateCourse) { - dispatch && - dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_COURSE_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_SAVED, + }); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -114,13 +119,17 @@ export function Details({ id, address, dispatch, profile }: DetailsProps) { dispatch && dispatch(networkAction(true)); const response = await fetch.exec(); if (response.updateCourse) { - dispatch && - dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_COURSE_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_SAVED, + }); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/blogs/editor/layout/header.tsx b/apps/web/components/admin/blogs/editor/layout/header.tsx index 73f4acf78..d5b5c4418 100644 --- a/apps/web/components/admin/blogs/editor/layout/header.tsx +++ b/apps/web/components/admin/blogs/editor/layout/header.tsx @@ -6,6 +6,7 @@ import { Menu2, Link, Breadcrumbs, + useToast, } from "@courselit/components-library"; import { DELETE_PRODUCT_POPUP_HEADER, @@ -42,6 +43,7 @@ export default function BlogHeader({ }: BlogHeaderProps) { const course = useCourse(id, address); const router = useRouter(); + const { toast } = useToast(); if (!course) { return <>; @@ -93,6 +95,7 @@ export default function BlogHeader({ onDeleteComplete: () => { router.replace(`/dashboard/blogs`); }, + toast, }) } > diff --git a/apps/web/components/admin/blogs/editor/publish.tsx b/apps/web/components/admin/blogs/editor/publish.tsx index b525e61e7..b42dedfde 100644 --- a/apps/web/components/admin/blogs/editor/publish.tsx +++ b/apps/web/components/admin/blogs/editor/publish.tsx @@ -1,16 +1,14 @@ import React, { FormEvent, useEffect, useState } from "react"; -import { Button, Form } from "@courselit/components-library"; +import { Button, Form, useToast } from "@courselit/components-library"; import useCourse from "./course-hook"; import { connect } from "react-redux"; import { capitalize, FetchBuilder } from "@courselit/utils"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; -import { Address, AppMessage } from "@courselit/common-models"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; +import { Address } from "@courselit/common-models"; import { BTN_PUBLISH, BTN_UNPUBLISH, + TOAST_TITLE_ERROR, PUBLISH_TAB_STATUS_SUBTITLE, PUBLISH_TAB_STATUS_TITLE, PUBLISH_TAB_VISIBILITY_SUBTITLE, @@ -29,6 +27,7 @@ export function Publish({ id, address, dispatch, loading }: PublishProps) { let course = useCourse(id, address, dispatch); const [published, setPublished] = useState(course?.published); const [privacy, setPrivacy] = useState(course?.privacy); + const { toast } = useToast(); useEffect(() => { if (course) { @@ -86,7 +85,11 @@ export function Publish({ id, address, dispatch, loading }: PublishProps) { return response.course; } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/blogs/helpers.ts b/apps/web/components/admin/blogs/helpers.ts index aa0b10195..5f4caaf01 100644 --- a/apps/web/components/admin/blogs/helpers.ts +++ b/apps/web/components/admin/blogs/helpers.ts @@ -1,23 +1,27 @@ -import { AppMessage } from "@courselit/common-models"; import { AppDispatch } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; -import { APP_MESSAGE_COURSE_DELETED } from "../../../ui-config/strings"; +import { + APP_MESSAGE_COURSE_DELETED, + TOAST_TITLE_ERROR, + TOAST_TITLE_SUCCESS, +} from "../../../ui-config/strings"; +import { useToast } from "@courselit/components-library"; interface DeleteProductProps { id: string; backend: string; dispatch?: AppDispatch; onDeleteComplete?: (...args: any[]) => void; + toast: ReturnType["toast"]; } + export const deleteProduct = async ({ id, backend, dispatch, onDeleteComplete, + toast, }: DeleteProductProps) => { const query = ` mutation { @@ -40,11 +44,18 @@ export const deleteProduct = async ({ // onDelete(position); } } catch (err: any) { - console.error(err); - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast && + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); - dispatch && - dispatch(setAppMessage(new AppMessage(APP_MESSAGE_COURSE_DELETED))); + toast && + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_DELETED, + }); } }; diff --git a/apps/web/components/admin/blogs/index.tsx b/apps/web/components/admin/blogs/index.tsx index 2aeaa1cd7..afa65a9b2 100644 --- a/apps/web/components/admin/blogs/index.tsx +++ b/apps/web/components/admin/blogs/index.tsx @@ -1,20 +1,13 @@ import React, { useCallback, useEffect, useState } from "react"; -import { - Address, - AppMessage, - Course, - SiteInfo, -} from "@courselit/common-models"; +import { Address, Course, SiteInfo } from "@courselit/common-models"; import { AppDispatch, AppState } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { connect } from "react-redux"; import { BLOG_TABLE_HEADER_NAME, BTN_NEW_BLOG, + TOAST_TITLE_ERROR, MANAGE_BLOG_PAGE_HEADING, PRODUCTS_TABLE_HEADER_ACTIONS, PRODUCTS_TABLE_HEADER_STATUS, @@ -22,10 +15,16 @@ import { } from "../../../ui-config/strings"; import dynamic from "next/dynamic"; import { MoreVert } from "@courselit/icons"; -import { MenuItem, Menu2, Button, Link } from "@courselit/components-library"; -import { Table } from "@courselit/components-library"; -import { TableHead } from "@courselit/components-library"; -import { TableBody } from "@courselit/components-library"; +import { + MenuItem, + Menu2, + Button, + Link, + Table, + TableHead, + TableBody, + useToast, +} from "@courselit/components-library"; import { usePathname } from "next/navigation"; const BlogItem = dynamic(() => import("./blog-item")); @@ -51,6 +50,7 @@ export const Index = ({ >([]); const [endReached, setEndReached] = useState(false); const path = usePathname(); + const { toast } = useToast(); const loadBlogs = useCallback(async () => { const query = ` @@ -85,7 +85,11 @@ export const Index = ({ } } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/blogs/new-blog.tsx b/apps/web/components/admin/blogs/new-blog.tsx index 00fd3fd13..48533d5e9 100644 --- a/apps/web/components/admin/blogs/new-blog.tsx +++ b/apps/web/components/admin/blogs/new-blog.tsx @@ -1,10 +1,11 @@ import React, { FormEvent, useState } from "react"; -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Form, FormField, Button, Breadcrumbs, + useToast, } from "@courselit/components-library"; import { AppDispatch, AppState } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; @@ -15,13 +16,11 @@ import { BTN_NEW_BLOG, BUTTON_CANCEL_TEXT, COURSE_TYPE_BLOG, + TOAST_TITLE_ERROR, FORM_NEW_PRODUCT_TITLE_PLC, MANAGE_BLOG_PAGE_HEADING, } from "@/ui-config/strings"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import Link from "next/link"; interface NewBlogProps { @@ -39,6 +38,7 @@ export function NewBlog({ }: NewBlogProps) { const [title, setTitle] = useState(""); const router = useRouter(); + const { toast } = useToast(); const createCourse = async (e: FormEvent) => { e.preventDefault(); @@ -70,7 +70,11 @@ export function NewBlog({ ); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/mails/broadcast-editor.tsx b/apps/web/components/admin/mails/broadcast-editor.tsx index 7f0a58233..198baa8d9 100644 --- a/apps/web/components/admin/mails/broadcast-editor.tsx +++ b/apps/web/components/admin/mails/broadcast-editor.tsx @@ -4,14 +4,14 @@ import { FormField, Breadcrumbs, Link, + Dialog2, + useToast, } from "@courselit/components-library"; -import { AppDispatch } from "@courselit/state-management"; +import { AppDispatch, actionCreators } from "@courselit/state-management"; import { ChangeEvent, FormEvent, useEffect, useState } from "react"; -import { actionCreators } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; import { Address, - AppMessage, Constants, SequenceReport, UserFilter, @@ -24,19 +24,19 @@ import { BUTTON_CANCEL_TEXT, DIALOG_SEND_HEADER, ERROR_DELAY_EMPTY, + TOAST_TITLE_ERROR, ERROR_SUBJECT_EMPTY, FORM_MAIL_SCHEDULE_TIME_LABEL, MAIL_SUBJECT_PLACEHOLDER, PAGE_HEADER_ALL_MAILS, PAGE_HEADER_EDIT_MAIL, TOAST_MAIL_SENT, + TOAST_TITLE_SUCCESS, } from "@ui-config/strings"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import FilterContainer from "@components/admin/users/filter-container"; import { useCallback } from "react"; import { useMemo } from "react"; import { PaperPlane, Clock } from "@courselit/icons"; -import { Dialog2 } from "@courselit/components-library"; import { isDateInFuture } from "../../../lib/utils"; import { MailEditorAndPreview } from "./mail-editor-and-preview"; const { networkAction } = actionCreators; @@ -63,6 +63,7 @@ function MailEditor({ id, address, dispatch, prefix }: MailEditorProps) { const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false); const [report, setReport] = useState(); const [status, setStatus] = useState(null); + const { toast } = useToast(); const fetch = useMemo( () => @@ -127,7 +128,11 @@ function MailEditor({ id, address, dispatch, prefix }: MailEditorProps) { setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); setLoaded(true); @@ -211,7 +216,11 @@ function MailEditor({ id, address, dispatch, prefix }: MailEditorProps) { dispatch && dispatch(networkAction(true)); await fetcher.exec(); } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -235,15 +244,21 @@ function MailEditor({ id, address, dispatch, prefix }: MailEditorProps) { e.preventDefault(); if (!subject.trim()) { - dispatch && - dispatch(setAppMessage(new AppMessage(ERROR_SUBJECT_EMPTY))); + toast({ + title: TOAST_TITLE_ERROR, + description: ERROR_SUBJECT_EMPTY, + variant: "destructive", + }); setConfirmationDialogOpen(false); return; } if (sendLater && delay === 0) { - dispatch && - dispatch(setAppMessage(new AppMessage(ERROR_DELAY_EMPTY))); + toast({ + title: TOAST_TITLE_ERROR, + description: ERROR_DELAY_EMPTY, + variant: "destructive", + }); setConfirmationDialogOpen(false); return; } @@ -320,11 +335,17 @@ function MailEditor({ id, address, dispatch, prefix }: MailEditorProps) { setReport(sequence.report); setStatus(sequence.status); setShowScheduleInput(false); - dispatch && - dispatch(setAppMessage(new AppMessage(TOAST_MAIL_SENT))); + toast({ + title: TOAST_TITLE_SUCCESS, + description: TOAST_MAIL_SENT, + }); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); setConfirmationDialogOpen(false); @@ -395,7 +416,11 @@ function MailEditor({ id, address, dispatch, prefix }: MailEditorProps) { setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/mails/index.tsx b/apps/web/components/admin/mails/index.tsx index 0464efa40..6cfd6064f 100644 --- a/apps/web/components/admin/mails/index.tsx +++ b/apps/web/components/admin/mails/index.tsx @@ -1,23 +1,25 @@ import React, { useEffect, useState } from "react"; import { Address, - AppMessage, Constants, Domain, Sequence, SequenceType, } from "@courselit/common-models"; -import { AppDispatch, AppState } from "@courselit/state-management"; +import { + AppDispatch, + AppState, + actionCreators, +} from "@courselit/state-management"; import { BTN_NEW_MAIL, PAGE_HEADER_ALL_MAILS, BROADCASTS, SEQUENCES, BTN_NEW_SEQUENCE, + TOAST_TITLE_ERROR, } from "../../../ui-config/strings"; import { FetchBuilder } from "@courselit/utils"; -import { actionCreators } from "@courselit/state-management"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import { useRouter } from "next/navigation"; import { ThunkDispatch } from "redux-thunk"; import { @@ -29,6 +31,7 @@ import { CardContent, CardFooter, CardTitle, + useToast, } from "@courselit/components-library"; import { AnyAction } from "redux"; import RequestForm from "./request-form"; @@ -63,6 +66,7 @@ export default function Mails({ >([]); const [siteInfo, setSiteInfo] = useState(); const router = useRouter(); + const { toast } = useToast(); const handleBroadcastPageChange = (newPage: number) => { setBroadcastPage(newPage); @@ -98,7 +102,11 @@ export default function Mails({ setSiteInfo(response.siteInfo); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -138,7 +146,11 @@ export default function Mails({ setBroadcasts(response.broadcasts); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -175,7 +187,11 @@ export default function Mails({ } } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -221,7 +237,11 @@ export default function Mails({ ); } } catch (err) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && (dispatch as ThunkDispatch)( diff --git a/apps/web/components/admin/mails/request-form.tsx b/apps/web/components/admin/mails/request-form.tsx index ee42144e4..49407569c 100644 --- a/apps/web/components/admin/mails/request-form.tsx +++ b/apps/web/components/admin/mails/request-form.tsx @@ -1,17 +1,21 @@ -import { Address, AppMessage } from "@courselit/common-models"; -import { Form, FormField, FormSubmit } from "@courselit/components-library"; -import { AppDispatch } from "@courselit/state-management"; +import { Address } from "@courselit/common-models"; import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; + Form, + FormField, + FormSubmit, + useToast, +} from "@courselit/components-library"; +import { AppDispatch } from "@courselit/state-management"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder, capitalize } from "@courselit/utils"; import { + TOAST_TITLE_ERROR, MAIL_REQUEST_FORM_REASON_FIELD, MAIL_REQUEST_FORM_REASON_PLACEHOLDER, MAIL_REQUEST_FORM_SUBMIT_INITIAL_REQUEST_TEXT, MAIL_REQUEST_FORM_SUBMIT_UPDATE_REQUEST_TEXT, MAIL_REQUEST_RECEIVED, + TOAST_TITLE_SUCCESS, } from "@ui-config/strings"; import { ChangeEvent, useEffect, useState } from "react"; @@ -25,6 +29,7 @@ const RequestForm = ({ address, dispatch, loading }: RequestFormProps) => { const [reason, setReason] = useState(""); const [message, setMessage] = useState(""); const [status, setStatus] = useState(""); + const { toast } = useToast(); useEffect(() => { const loadMailRequestStatus = async () => { @@ -53,7 +58,11 @@ const RequestForm = ({ address, dispatch, loading }: RequestFormProps) => { setStatus(status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -95,13 +104,17 @@ const RequestForm = ({ address, dispatch, loading }: RequestFormProps) => { dispatch && dispatch(networkAction(true)); const response = await fetch.exec(); if (response.updateMailRequest) { - dispatch && - dispatch( - setAppMessage(new AppMessage(MAIL_REQUEST_RECEIVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: MAIL_REQUEST_RECEIVED, + }); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/mails/sequence-editor-2.tsx b/apps/web/components/admin/mails/sequence-editor-2.tsx index 16bce46aa..23bafa1b2 100644 --- a/apps/web/components/admin/mails/sequence-editor-2.tsx +++ b/apps/web/components/admin/mails/sequence-editor-2.tsx @@ -1,4 +1,9 @@ -import { Form, FormField, Section } from "@courselit/components-library"; +import { + Form, + FormField, + Section, + useToast, +} from "@courselit/components-library"; import { AppDispatch, AppState } from "@courselit/state-management"; import { ChangeEvent, FormEvent, useEffect, useState } from "react"; import { actionCreators } from "@courselit/state-management"; @@ -7,24 +12,20 @@ import { FetchBuilder, getGraphQLQueryStringFromObject, } from "@courselit/utils"; -import { - Address, - AppMessage, - Mail, - UIConstants, -} from "@courselit/common-models"; +import { Address, Mail, UIConstants } from "@courselit/common-models"; import { connect } from "react-redux"; import { BTN_SEND, BTN_SENDING, + TOAST_TITLE_ERROR, MAIL_BODY_PLACEHOLDER, MAIL_SUBJECT_PLACEHOLDER, MAIL_TO_PLACEHOLDER, PAGE_HEADER_ALL_MAILS, PAGE_HEADER_EDIT_MAIL, TOAST_MAIL_SENT, + TOAST_TITLE_SUCCESS, } from "../../../ui-config/strings"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import { Breadcrumbs, Link, Button } from "@courselit/components-library"; const { networkAction } = actionCreators; @@ -43,6 +44,7 @@ function MailEditor({ id, address, dispatch }: MailEditorProps) { published: false, }); const [sending, setSending] = useState(false); + const { toast } = useToast(); const debouncedSave = debounce(async () => await saveMail(), 1000); useEffect(() => { @@ -86,7 +88,11 @@ function MailEditor({ id, address, dispatch }: MailEditorProps) { }); } } catch (e: any) { - dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -108,7 +114,11 @@ function MailEditor({ id, address, dispatch }: MailEditorProps) { dispatch(networkAction(true)); await fetcher.exec(); } catch (e: any) { - dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -145,9 +155,16 @@ function MailEditor({ id, address, dispatch }: MailEditorProps) { if (response.mail) { setMail(response.mail); } - dispatch(setAppMessage(new AppMessage(TOAST_MAIL_SENT))); + toast({ + title: TOAST_TITLE_SUCCESS, + description: TOAST_MAIL_SENT, + }); } catch (e: any) { - dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); setSending(false); diff --git a/apps/web/components/admin/mails/sequence-editor.tsx b/apps/web/components/admin/mails/sequence-editor.tsx index c8e02ec10..86342be3d 100644 --- a/apps/web/components/admin/mails/sequence-editor.tsx +++ b/apps/web/components/admin/mails/sequence-editor.tsx @@ -1,9 +1,4 @@ -import { - Address, - AppMessage, - Constants, - Course, -} from "@courselit/common-models"; +import { Address, Constants, Course } from "@courselit/common-models"; import { Breadcrumbs, Form, @@ -15,15 +10,13 @@ import { MenuItem, FormSubmit, Skeleton, + useToast, } from "@courselit/components-library"; import { Pause } from "@courselit/icons"; import { Play } from "@courselit/icons"; import { Add, MoreVert } from "@courselit/icons"; import { AppDispatch } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { COMPOSE_SEQUENCE_ENTRANCE_CONDITION, @@ -32,6 +25,7 @@ import { COMPOSE_SEQUENCE_FORM_TITLE, COMPOSE_SEQUENCE_FROM_PLC, DELETE_EMAIL_MENU, + TOAST_TITLE_ERROR, PAGE_HEADER_ALL_MAILS, PAGE_HEADER_EDIT_SEQUENCE, } from "@ui-config/strings"; @@ -76,6 +70,7 @@ const SequenceEditor = ({ >([]); const [emailsOrder, setEmailsOrder] = useState([]); const [status, setStatus] = useState(null); + const { toast } = useToast(); const onSubmit = async (e: FormEvent, sendLater: boolean = false) => { e.preventDefault(); @@ -136,7 +131,11 @@ const SequenceEditor = ({ setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); // setLoaded(true); @@ -199,7 +198,11 @@ const SequenceEditor = ({ setProducts([...response.courses]); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }, [dispatch, fetch]); @@ -248,7 +251,11 @@ const SequenceEditor = ({ setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); // setLoaded(true); @@ -325,7 +332,11 @@ const SequenceEditor = ({ setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); // setLoaded(true); @@ -426,7 +437,11 @@ const SequenceEditor = ({ setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); // setLoaded(true); @@ -493,7 +508,11 @@ const SequenceEditor = ({ setStatus(sequence.status); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); // setLoaded(true); diff --git a/apps/web/components/admin/mails/sequence-mail-editor.tsx b/apps/web/components/admin/mails/sequence-mail-editor.tsx index 557fb0487..54de22009 100644 --- a/apps/web/components/admin/mails/sequence-mail-editor.tsx +++ b/apps/web/components/admin/mails/sequence-mail-editor.tsx @@ -1,4 +1,4 @@ -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Breadcrumbs, Button, @@ -6,16 +6,15 @@ import { FormField, Link, Select, + useToast, } from "@courselit/components-library"; import { AppDispatch } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { BUTTON_SAVE, COMPOSE_SEQUENCE_EDIT_DELAY, + TOAST_TITLE_ERROR, MAIL_PREVIEW_TITLE, MAIL_SUBJECT_PLACEHOLDER, PAGE_HEADER_ALL_MAILS, @@ -50,7 +49,7 @@ const SequenceMailEditor = ({ const [published, setPublished] = useState<"unpublished" | "published">( null, ); - + const { toast } = useToast(); const fetch = useMemo( () => new FetchBuilder() @@ -106,7 +105,11 @@ const SequenceMailEditor = ({ } } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -196,7 +199,11 @@ const SequenceMailEditor = ({ } } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/mails/sequences-list.tsx b/apps/web/components/admin/mails/sequences-list.tsx index be26353af..e0943cdbd 100644 --- a/apps/web/components/admin/mails/sequences-list.tsx +++ b/apps/web/components/admin/mails/sequences-list.tsx @@ -2,7 +2,6 @@ import { Address, - AppMessage, Constants, Sequence, SequenceType, @@ -14,14 +13,13 @@ import { TableBody, TableHead, TableRow, + useToast, } from "@courselit/components-library"; import { AppDispatch } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder, capitalize } from "@courselit/utils"; import { + TOAST_TITLE_ERROR, MAIL_TABLE_HEADER_STATUS, MAIL_TABLE_HEADER_SUBJECT, } from "@ui-config/strings"; @@ -49,6 +47,7 @@ const SequencesList = ({ const [sequences, setSequences] = useState< Pick[] >([]); + const { toast } = useToast(); const handlePageChange = (newPage: number) => { setPage(newPage); @@ -101,7 +100,11 @@ const SequencesList = ({ setSequences(response.broadcasts); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -129,7 +132,11 @@ const SequencesList = ({ setCount(response.count); } } catch (e: any) { - dispatch && dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/my-content/content-card.tsx b/apps/web/components/admin/my-content/content-card.tsx index 2ea0d5752..9d37c0835 100644 --- a/apps/web/components/admin/my-content/content-card.tsx +++ b/apps/web/components/admin/my-content/content-card.tsx @@ -29,7 +29,7 @@ export function ContentCard({ item }: ContentCardProps) {

{entity.title}

- {entityType === "course" && entity.totalLessons && ( + {entityType === "course" && entity.totalLessons ? (

@@ -37,7 +37,7 @@ export function ContentCard({ item }: ContentCardProps) { {`${Math.round(progress)}%`}

- )} + ) : null}
); diff --git a/apps/web/components/admin/page-editor/index.tsx b/apps/web/components/admin/page-editor/index.tsx index e24fd94b4..02fc453c1 100644 --- a/apps/web/components/admin/page-editor/index.tsx +++ b/apps/web/components/admin/page-editor/index.tsx @@ -1,6 +1,5 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import { - AppMessage, Page, SiteInfo, Typeface, @@ -8,10 +7,7 @@ import { } from "@courselit/common-models"; import type { Address, Media, Profile } from "@courselit/common-models"; import type { AppDispatch, AppState } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { debounce, FetchBuilder, @@ -24,6 +20,7 @@ import { PAGE_TITLE_EDIT_PAGE, EDIT_PAGE_BUTTON_FONTS, EDIT_PAGE_BUTTON_SEO, + TOAST_TITLE_ERROR, EDIT_PAGE_BUTTON_VIEW, } from "../../../ui-config/strings"; import { useRouter } from "next/navigation"; @@ -37,7 +34,7 @@ import dynamic from "next/dynamic"; import Head from "next/head"; import widgets from "../../../ui-config/widgets"; import { Sync, CheckCircled } from "@courselit/icons"; -import { Button, Skeleton } from "@courselit/components-library"; +import { Button, Skeleton, useToast } from "@courselit/components-library"; import SeoEditor from "./seo-editor"; import { ArrowUpFromLine, Eye, LogOut } from "lucide-react"; @@ -95,6 +92,7 @@ export default function PageEditor({ const [primaryFontFamily, setPrimaryFontFamily] = useState("Roboto, sans-serif"); const [loading, setLoading] = useState(false); + const { toast } = useToast(); const router = useRouter(); const debouncedSave = useCallback( @@ -245,7 +243,11 @@ export default function PageEditor({ setDraftTypefaces(response.site.draftTypefaces); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -282,16 +284,19 @@ export default function PageEditor({ } setPage(pageBeingEdited); } else { - dispatch && - dispatch( - setAppMessage( - new AppMessage(`The page does not exist.`), - ), - ); + toast({ + title: TOAST_TITLE_ERROR, + description: `The page does not exist.`, + variant: "destructive", + }); router.replace(`${prefix}/pages`); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -489,7 +494,11 @@ export default function PageEditor({ setDraftTypefaces(response.site.draftTypefaces); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/pages/index.tsx b/apps/web/components/admin/pages/index.tsx index 7d1e291d0..a722826e5 100644 --- a/apps/web/components/admin/pages/index.tsx +++ b/apps/web/components/admin/pages/index.tsx @@ -1,5 +1,10 @@ -import { Address, AppMessage, Page } from "@courselit/common-models"; -import { Menu2, MenuItem, TableBody } from "@courselit/components-library"; +import { Address, Page } from "@courselit/common-models"; +import { + Menu2, + MenuItem, + TableBody, + useToast, +} from "@courselit/components-library"; import { TableRow } from "@courselit/components-library"; import { TableHead } from "@courselit/components-library"; import { Table } from "@courselit/components-library"; @@ -7,22 +12,21 @@ import { Button, Link } from "@courselit/components-library"; import { View } from "@courselit/icons"; import { Edit, MoreVert } from "@courselit/icons"; import { AppDispatch, AppState } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { APP_MESSAGE_PAGE_DELETED, BTN_NEW_PAGE, DELETE_PAGE_POPUP_HEADER, DELETE_PAGE_POPUP_TEXT, + TOAST_TITLE_ERROR, MANAGE_PAGES_PAGE_HEADING, PAGES_TABLE_HEADER_ACTIONS, PAGES_TABLE_HEADER_NAME, PAGE_TABLE_CONTEXT_MENU_DELETE, PAGE_TITLE_EDIT_PAGE, PAGE_TITLE_VIEW_PAGE, + TOAST_TITLE_SUCCESS, } from "@ui-config/strings"; import { useEffect, useState } from "react"; import { connect } from "react-redux"; @@ -36,6 +40,7 @@ interface IndexProps { export const Pages = ({ loading, address, dispatch, prefix }: IndexProps) => { const [pages, setPages] = useState([]); + const { toast } = useToast(); useEffect(() => { loadPages(); @@ -64,7 +69,11 @@ export const Pages = ({ loading, address, dispatch, prefix }: IndexProps) => { setPages(response.pages); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -93,9 +102,16 @@ export const Pages = ({ loading, address, dispatch, prefix }: IndexProps) => { setPages([...pages]); } - dispatch(setAppMessage(new AppMessage(APP_MESSAGE_PAGE_DELETED))); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_PAGE_DELETED, + }); } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/pages/new-page.tsx b/apps/web/components/admin/pages/new-page.tsx index 87cbddfba..0661aeb23 100644 --- a/apps/web/components/admin/pages/new-page.tsx +++ b/apps/web/components/admin/pages/new-page.tsx @@ -1,4 +1,4 @@ -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { AppDispatch } from "@courselit/state-management"; import { Form, @@ -10,7 +10,7 @@ import { import { BTN_CONTINUE, BUTTON_CANCEL_TEXT, - ERROR_SNACKBAR_PREFIX, + TOAST_TITLE_ERROR, NEW_PAGE_FORM_WARNING, NEW_PAGE_HEADING, NEW_PAGE_NAME_PLC, @@ -20,10 +20,7 @@ import { } from "@ui-config/strings"; import { FormEvent, useEffect, useState } from "react"; import { FetchBuilder, slugify } from "@courselit/utils"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { Info } from "@courselit/icons"; import { useRouter } from "next/navigation"; @@ -72,10 +69,10 @@ const NewPage = ({ ); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); toast({ - title: ERROR_SNACKBAR_PREFIX, + title: TOAST_TITLE_ERROR, description: err.message, + variant: "destructive", }); } finally { dispatch && dispatch(networkAction(false)); diff --git a/apps/web/components/admin/products/editor/content/lesson.tsx b/apps/web/components/admin/products/editor/content/lesson.tsx index b0b8b2202..ec259bf51 100644 --- a/apps/web/components/admin/products/editor/content/lesson.tsx +++ b/apps/web/components/admin/products/editor/content/lesson.tsx @@ -18,6 +18,8 @@ import { LESSON_CONTENT_EMBED_PLACEHOLDER, BUTTON_SAVING, MANAGE_COURSES_PAGE_HEADING, + TOAST_TITLE_ERROR, + TOAST_TITLE_SUCCESS, } from "@ui-config/strings"; import { LESSON_TYPE_TEXT, @@ -34,7 +36,7 @@ import { LESSON_TYPE_EMBED, } from "@ui-config/constants"; import { FetchBuilder, capitalize } from "@courselit/utils"; -import { AppMessage, Media, Profile, Quiz } from "@courselit/common-models"; +import { Media, Profile, Quiz } from "@courselit/common-models"; import type { AppDispatch } from "@courselit/state-management"; import type { Lesson, @@ -60,10 +62,11 @@ import { IconButton, Breadcrumbs, Skeleton, + useToast, } from "@courselit/components-library"; import { QuizBuilder } from "./quiz-builder"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface LessonEditorProps { courseId: string; @@ -112,6 +115,7 @@ const LessonEditor = ({ b1: false, }); const course = useCourse(courseId, address, dispatch); + const { toast } = useToast(); useEffect(() => { lessonId && loadLesson(lessonId); @@ -180,7 +184,11 @@ const LessonEditor = ({ } } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -220,8 +228,16 @@ const LessonEditor = ({ dispatch && dispatch(networkAction(true)); setLoading(true); await fetch.exec(); + toast({ + title: TOAST_TITLE_SUCCESS, + description: "Lesson updated", + }); } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); setLoading(false); @@ -260,8 +276,16 @@ const LessonEditor = ({ dispatch && dispatch(networkAction(true)); setLoading(true); await fetch.exec(); + toast({ + title: TOAST_TITLE_SUCCESS, + description: "Lesson updated", + }); } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); setLoading(false); @@ -313,7 +337,11 @@ const LessonEditor = ({ ); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); setLoading(false); @@ -339,19 +367,20 @@ const LessonEditor = ({ const response = await fetch.exec(); if (response.result) { - dispatch && - dispatch( - setAppMessage( - new AppMessage(APP_MESSAGE_LESSON_DELETED), - ), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_LESSON_DELETED, + }); router.replace( `${prefix}/product/${courseId}${prefix === "/dashboard" ? "/content" : "?tab=Content"}`, ); } } catch (err: any) { - dispatch && - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { setLoading(false); } diff --git a/apps/web/components/admin/products/editor/content/lessons-list.tsx b/apps/web/components/admin/products/editor/content/lessons-list.tsx index bad27660d..4950b2ca9 100644 --- a/apps/web/components/admin/products/editor/content/lessons-list.tsx +++ b/apps/web/components/admin/products/editor/content/lessons-list.tsx @@ -4,11 +4,12 @@ import { BUTTON_NEW_LESSON_TEXT, DELETE_SECTION_HEADER, EDIT_SECTION_HEADER, + TOAST_TITLE_ERROR, LESSON_GROUP_DELETED, } from "../../../../../ui-config/strings"; import { CourseWithAdminProps } from "../course-hook"; import { Add, MoreVert } from "@courselit/icons"; -import { Lesson, Address, AppMessage, Group } from "@courselit/common-models"; +import { Lesson, Address, Group } from "@courselit/common-models"; import { Section, Link, @@ -29,6 +30,7 @@ interface LessonSectionProps { address: Address; dispatch?: AppDispatch; prefix: string; + toast: ReturnType["toast"]; } function LessonItem({ @@ -61,6 +63,7 @@ function LessonSection({ address, dispatch, prefix, + toast, }: LessonSectionProps) { const updateGroup = async (lessonsOrder: string[]) => { const mutation = ` @@ -91,10 +94,11 @@ function LessonSection({ dispatch && dispatch(actionCreators.networkAction(true)); const response = await fetch.exec(); } catch (err: any) { - dispatch && - dispatch( - actionCreators.setAppMessage(new AppMessage(err.message)), - ); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(actionCreators.networkAction(false)); } @@ -208,12 +212,6 @@ export default function LessonsList({ dispatch && dispatch(actionCreators.networkAction(true)); const response = await fetch.exec(); if (response.removeGroup?.courseId) { - dispatch && - dispatch( - actionCreators.setAppMessage( - new AppMessage(LESSON_GROUP_DELETED), - ), - ); toast({ title: "", description: LESSON_GROUP_DELETED, @@ -224,10 +222,11 @@ export default function LessonsList({ ); } } catch (err: any) { - dispatch && - dispatch( - actionCreators.setAppMessage(new AppMessage(err.message)), - ); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(actionCreators.networkAction(false)); } @@ -248,6 +247,7 @@ export default function LessonsList({ address={address} dispatch={dispatch} prefix={prefix} + toast={toast} /> ))}
diff --git a/apps/web/components/admin/products/editor/course-hook.ts b/apps/web/components/admin/products/editor/course-hook.ts index a4c1e7bb6..3eeb0ebf5 100644 --- a/apps/web/components/admin/products/editor/course-hook.ts +++ b/apps/web/components/admin/products/editor/course-hook.ts @@ -1,12 +1,11 @@ import { Address } from "@courselit/common-models"; -import { AppMessage, Lesson } from "@courselit/common-models"; +import { Lesson } from "@courselit/common-models"; +import { useToast } from "@courselit/components-library"; import { AppDispatch } from "@courselit/state-management"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { Course } from "@models/Course"; +import { TOAST_TITLE_ERROR } from "@ui-config/strings"; import { useCallback, useEffect, useState } from "react"; export type CourseWithAdminProps = Partial< @@ -24,6 +23,7 @@ export default function useCourse( const [course, setCourse] = useState< CourseWithAdminProps | undefined | null >(); + const { toast } = useToast(); const loadCourse = useCallback( async (courseId: string) => { @@ -92,8 +92,11 @@ export default function useCourse( } } catch (err: any) { setCourse(null); - dispatch && - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/products/editor/details.tsx b/apps/web/components/admin/products/editor/details.tsx index 087ee388a..fc95494a7 100644 --- a/apps/web/components/admin/products/editor/details.tsx +++ b/apps/web/components/admin/products/editor/details.tsx @@ -7,19 +7,19 @@ import { Form, FormField, PageBuilderPropertyHeader, + useToast, } from "@courselit/components-library"; import useCourse from "./course-hook"; import { FetchBuilder } from "@courselit/utils"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; -import { Address, AppMessage, Media, Profile } from "@courselit/common-models"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; +import { Address, Media, Profile } from "@courselit/common-models"; import { APP_MESSAGE_COURSE_SAVED, BUTTON_SAVE, COURSE_CONTENT_HEADER, + TOAST_TITLE_ERROR, FORM_FIELD_FEATURED_IMAGE, + TOAST_TITLE_SUCCESS, } from "../../../../ui-config/strings"; import { AppDispatch } from "@courselit/state-management"; import { MIMETYPE_IMAGE } from "../../../../ui-config/constants"; @@ -42,6 +42,7 @@ export default function Details({ const [featuredImage, setFeaturedImage] = useState>({}); const [refresh, setRefresh] = useState(0); const course = useCourse(id, address, dispatch); + const { toast } = useToast(); useEffect(() => { if (course) { @@ -79,13 +80,17 @@ export default function Details({ dispatch && dispatch(networkAction(true)); const response = await fetch.exec(); if (response.updateCourse) { - dispatch && - dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_COURSE_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_SAVED, + }); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -117,13 +122,17 @@ export default function Details({ dispatch && dispatch(networkAction(true)); const response = await fetch.exec(); if (response.updateCourse) { - dispatch && - dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_COURSE_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_SAVED, + }); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/products/editor/pricing.tsx b/apps/web/components/admin/products/editor/pricing.tsx index 254de223a..7b16e9725 100644 --- a/apps/web/components/admin/products/editor/pricing.tsx +++ b/apps/web/components/admin/products/editor/pricing.tsx @@ -1,11 +1,14 @@ import React, { FormEvent, useEffect, useState } from "react"; -import { Address, AppMessage, SiteInfo } from "@courselit/common-models"; -import { FormField, Form, Button } from "@courselit/components-library"; -import type { AppDispatch } from "@courselit/state-management"; +import { Address, SiteInfo } from "@courselit/common-models"; import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; + FormField, + Form, + Button, + Select, + useToast, +} from "@courselit/components-library"; +import type { AppDispatch } from "@courselit/state-management"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { APP_MESSAGE_COURSE_SAVED, @@ -21,9 +24,10 @@ import { PRICING_PAID_LABEL, PRICING_PAID_NO_PAYMENT_METHOD, PRICING_PAID_SUBTITLE, + TOAST_TITLE_ERROR, + TOAST_TITLE_SUCCESS, } from "../../../../ui-config/strings"; import useCourse from "./course-hook"; -import { Select } from "@courselit/components-library"; import { COURSE_TYPE_DOWNLOAD } from "../../../../ui-config/constants"; interface PricingProps { @@ -44,6 +48,7 @@ export default function Pricing({ const [costType, setCostType] = useState( course?.costType?.toLowerCase() || PRICING_FREE, ); + const { toast } = useToast(); useEffect(() => { if (course) { @@ -75,13 +80,17 @@ export default function Pricing({ dispatch && dispatch(networkAction(true)); const response = await fetch.exec(); if (response.updateCourse) { - dispatch && - dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_COURSE_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_SAVED, + }); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/products/editor/publish.tsx b/apps/web/components/admin/products/editor/publish.tsx index f5f7f0866..4f246853b 100644 --- a/apps/web/components/admin/products/editor/publish.tsx +++ b/apps/web/components/admin/products/editor/publish.tsx @@ -1,12 +1,12 @@ import React, { FormEvent, useEffect, useState } from "react"; -import { Form, Button } from "@courselit/components-library"; +import { Form, Button, useToast } from "@courselit/components-library"; import useCourse from "./course-hook"; import { capitalize, FetchBuilder } from "@courselit/utils"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { BTN_PUBLISH, BTN_UNPUBLISH, + TOAST_TITLE_ERROR, PUBLISH_TAB_STATUS_SUBTITLE, PUBLISH_TAB_STATUS_TITLE, PUBLISH_TAB_VISIBILITY_SUBTITLE, @@ -25,6 +25,7 @@ export default function Publish({ id, address, dispatch }: PublishProps) { const [published, setPublished] = useState(course?.published); const [privacy, setPrivacy] = useState(course?.privacy as string); const [loading, setLoading] = useState(false); + const { toast } = useToast(); useEffect(() => { if (course) { @@ -82,7 +83,11 @@ export default function Publish({ id, address, dispatch }: PublishProps) { return response.course; } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { setLoading(false); } diff --git a/apps/web/components/admin/products/editor/section.tsx b/apps/web/components/admin/products/editor/section.tsx index eaa5d6857..d5327ee38 100644 --- a/apps/web/components/admin/products/editor/section.tsx +++ b/apps/web/components/admin/products/editor/section.tsx @@ -1,9 +1,4 @@ -import { - Address, - AppMessage, - Constants, - DripType, -} from "@courselit/common-models"; +import { Address, Constants, DripType } from "@courselit/common-models"; import { Button, Form, @@ -11,6 +6,7 @@ import { Section, Skeleton, Switch, + useToast, } from "@courselit/components-library"; import { actionCreators, AppDispatch } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; @@ -22,6 +18,7 @@ import { DRIP_SECTION_STATUS, EDIT_SECTION_DRIP, EDIT_SECTION_HEADER, + TOAST_TITLE_ERROR, LABEL_DRIP_DATE, LABEL_DRIP_DELAY, LABEL_DRIP_EMAIL_SUBJECT, @@ -61,6 +58,7 @@ export default function SectionEditor({ const [emailSubject, setEmailSubject] = useState(""); const router = useRouter(); const course = useCourse(id, address, dispatch); + const { toast } = useToast(); useEffect(() => { if (section && course && course.groups) { @@ -192,10 +190,11 @@ export default function SectionEditor({ ); } } catch (err: any) { - dispatch && - dispatch( - actionCreators.setAppMessage(new AppMessage(err.message)), - ); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(actionCreators.networkAction(false)); } diff --git a/apps/web/components/admin/products/index.tsx b/apps/web/components/admin/products/index.tsx index c38e37116..26ea17701 100644 --- a/apps/web/components/admin/products/index.tsx +++ b/apps/web/components/admin/products/index.tsx @@ -9,10 +9,10 @@ import { PRODUCTS_TABLE_HEADER_ACTIONS, BTN_NEW_PRODUCT, PRODUCTS_TABLE_HEADER_TYPE, + TOAST_TITLE_ERROR, } from "../../../ui-config/strings"; import { FetchBuilder } from "@courselit/utils"; import type { Address, SiteInfo } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; import type { AppDispatch, AppState } from "@courselit/state-management"; import { actionCreators } from "@courselit/state-management"; import Product, { CourseDetails } from "./product"; @@ -22,9 +22,10 @@ import { Table, TableHead, TableBody, + useToast, } from "@courselit/components-library"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface IndexProps { dispatch?: AppDispatch; @@ -46,6 +47,7 @@ export const Index = ({ const [searchText, setSearchText] = useState(""); const [searchState, setSearchState] = useState(0); const [endReached, setEndReached] = useState(false); + const { toast } = useToast(); useEffect(() => { loadCreatorCourses(); @@ -116,7 +118,11 @@ export const Index = ({ } } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/products/new-customer.tsx b/apps/web/components/admin/products/new-customer.tsx index aa3a9a044..e41270f05 100644 --- a/apps/web/components/admin/products/new-customer.tsx +++ b/apps/web/components/admin/products/new-customer.tsx @@ -1,7 +1,7 @@ "use client"; import React, { useCallback, useEffect, useState } from "react"; -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Form, FormField, @@ -16,13 +16,12 @@ import { FetchBuilder } from "@courselit/utils"; import { BTN_GO_BACK, BTN_INVITE, + TOAST_TITLE_ERROR, PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER, USER_TAGS_SUBHEADER, + TOAST_TITLE_SUCCESS, } from "@/ui-config/strings"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import useCourse from "./editor/course-hook"; interface NewCustomerProps { @@ -108,17 +107,16 @@ export default function NewCustomer({ setEmail(""); setTags([]); const message = `${response.user.email} has been invited.`; - dispatch && dispatch(setAppMessage(new AppMessage(message))); toast({ - title: "Success", + title: TOAST_TITLE_SUCCESS, description: message, }); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); toast({ - title: "Error", + title: TOAST_TITLE_ERROR, description: err.message, + variant: "destructive", }); } finally { dispatch && dispatch(networkAction(false)); diff --git a/apps/web/components/admin/products/new-product.tsx b/apps/web/components/admin/products/new-product.tsx index 18720b24c..ee939c6e5 100644 --- a/apps/web/components/admin/products/new-product.tsx +++ b/apps/web/components/admin/products/new-product.tsx @@ -1,5 +1,5 @@ import React, { FormEvent, useState } from "react"; -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Form, FormField, @@ -7,6 +7,7 @@ import { Link, Button, Breadcrumbs, + useToast, } from "@courselit/components-library"; import { AppDispatch, AppState } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; @@ -20,6 +21,7 @@ import { BTN_CONTINUE, BTN_NEW_PRODUCT, BUTTON_CANCEL_TEXT, + TOAST_TITLE_ERROR, FORM_NEW_PRODUCT_MENU_COURSE_SUBTITLE, FORM_NEW_PRODUCT_MENU_DOWNLOADS_SUBTITLE, FORM_NEW_PRODUCT_TITLE_PLC, @@ -27,10 +29,7 @@ import { MANAGE_COURSES_PAGE_HEADING, } from "../../../ui-config/strings"; import { capitalize } from "../../../ui-lib/utils"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { usePathname } from "next/navigation"; interface NewProductProps { @@ -50,6 +49,7 @@ export function NewProduct({ const [type, setType] = useState(COURSE_TYPE_COURSE); const router = useRouter(); const path = usePathname(); + const { toast } = useToast(); const createCourse = async (e: FormEvent) => { e.preventDefault(); @@ -81,7 +81,11 @@ export function NewProduct({ ); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/products/product.tsx b/apps/web/components/admin/products/product.tsx index d15b5908a..923cb75b8 100644 --- a/apps/web/components/admin/products/product.tsx +++ b/apps/web/components/admin/products/product.tsx @@ -1,30 +1,30 @@ import React from "react"; -import { AppMessage, Course } from "@courselit/common-models"; +import { Course } from "@courselit/common-models"; import { APP_MESSAGE_COURSE_DELETED, DELETE_PRODUCT_POPUP_HEADER, DELETE_PRODUCT_POPUP_TEXT, + TOAST_TITLE_ERROR, PRODUCT_STATUS_DRAFT, PRODUCT_STATUS_PUBLISHED, PRODUCT_TABLE_CONTEXT_MENU_DELETE_PRODUCT, PRODUCT_TABLE_CONTEXT_MENU_EDIT_PAGE, PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER, VIEW_PAGE_MENU_ITEM, + TOAST_TITLE_SUCCESS, } from "../../../ui-config/strings"; import { MoreVert } from "@courselit/icons"; import type { AppDispatch } from "@courselit/state-management"; import type { SiteInfo, Address } from "@courselit/common-models"; import { capitalize, FetchBuilder, formatCurrency } from "@courselit/utils"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { Menu2, MenuItem, Link, Chip, TableRow, + useToast, } from "@courselit/components-library"; import { usePathname } from "next/navigation"; @@ -54,6 +54,7 @@ export default function Product({ }) { const product = details; const path = usePathname(); + const { toast } = useToast(); const deleteProduct = async () => { const query = ` @@ -76,13 +77,17 @@ export default function Product({ onDelete(position); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); - dispatch && - dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_COURSE_DELETED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_COURSE_DELETED, + }); } }; diff --git a/apps/web/components/admin/settings/apikey/new.tsx b/apps/web/components/admin/settings/apikey/new.tsx index feac13065..2e4b9ecb2 100644 --- a/apps/web/components/admin/settings/apikey/new.tsx +++ b/apps/web/components/admin/settings/apikey/new.tsx @@ -1,10 +1,11 @@ -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Breadcrumbs, Button, Form, FormField, IconButton, + useToast, } from "@courselit/components-library"; import { AppDispatch } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; @@ -17,13 +18,12 @@ import { APIKEY_NEW_LABEL, BUTTON_CANCEL_TEXT, BUTTON_DONE_TEXT, + TOAST_TITLE_ERROR, + TOAST_TITLE_SUCCESS, } from "@ui-config/strings"; import Link from "next/link"; import { FormEvent, useState } from "react"; -import { - networkAction, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { networkAction } from "@courselit/state-management/dist/action-creators"; import { Clipboard } from "@courselit/icons"; interface NewApikeyProps { @@ -41,18 +41,17 @@ export default function NewApikey({ }: NewApikeyProps) { const [name, setName] = useState(""); const [apikey, setApikey] = useState(""); + const { toast } = useToast(); const copyApikey = (e: FormEvent) => { e.preventDefault(); if (window.isSecureContext && navigator.clipboard) { navigator.clipboard.writeText(apikey); - dispatch && - dispatch( - setAppMessage( - new AppMessage(APIKEY_NEW_GENERATED_KEY_COPIED), - ), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APIKEY_NEW_GENERATED_KEY_COPIED, + }); } }; @@ -82,7 +81,11 @@ export default function NewApikey({ setApikey(response.apikey.key); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/settings/index.tsx b/apps/web/components/admin/settings/index.tsx index a89cc0c19..32bfa418b 100644 --- a/apps/web/components/admin/settings/index.tsx +++ b/apps/web/components/admin/settings/index.tsx @@ -45,7 +45,7 @@ import { } from "@/ui-config/strings"; import { FetchBuilder, capitalize } from "@courselit/utils"; import { decode, encode } from "base-64"; -import { AppMessage, Profile, UIConstants } from "@courselit/common-models"; +import { Profile, UIConstants } from "@courselit/common-models"; import type { SiteInfo, Address, Media } from "@courselit/common-models"; import { actionCreators } from "@courselit/state-management"; import currencies from "@/data/currencies.json"; @@ -87,7 +87,7 @@ const { MIMETYPE_IMAGE, } = UIConstants; -const { networkAction, newSiteInfoAvailable, setAppMessage } = actionCreators; +const { networkAction, newSiteInfoAvailable } = actionCreators; interface SettingsProps { siteinfo: SiteInfo; @@ -281,12 +281,17 @@ const Settings = (props: SettingsProps) => { const response = await fetchRequest.exec(); if (response.settings.settings) { setSettingsState(response.settings.settings); - props.dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_SETTINGS_SAVED, + }); } } catch (e: any) { - props.dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { props.dispatch(networkAction(false)); } @@ -336,12 +341,17 @@ const Settings = (props: SettingsProps) => { const response = await fetchRequest.exec(); if (response.settings.settings) { setSettingsState(response.settings.settings); - props.dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_SETTINGS_SAVED, + }); } } catch (e: any) { - props.dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { props.dispatch(networkAction(false)); } @@ -393,12 +403,17 @@ const Settings = (props: SettingsProps) => { const response = await fetchRequest.exec(); if (response.settings.settings) { setSettingsState(response.settings.settings); - props.dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_SETTINGS_SAVED, + }); } } catch (e: any) { - props.dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { props.dispatch(networkAction(false)); } @@ -449,16 +464,12 @@ const Settings = (props: SettingsProps) => { const response = await fetchRequest.exec(); if (response.settings.settings) { setSettingsState(response.settings.settings); - props.dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)), - ); toast({ title: TOAST_TITLE_SUCCESS, description: APP_MESSAGE_SETTINGS_SAVED, }); } } catch (e: any) { - props.dispatch(setAppMessage(new AppMessage(e.message))); toast({ title: TOAST_TITLE_ERROR, description: e.message, @@ -550,16 +561,12 @@ const Settings = (props: SettingsProps) => { const response = await fetchRequest.exec(); if (response.settings.settings) { setSettingsState(response.settings.settings); - props.dispatch( - setAppMessage(new AppMessage(APP_MESSAGE_SETTINGS_SAVED)), - ); toast({ title: TOAST_TITLE_SUCCESS, description: APP_MESSAGE_SETTINGS_SAVED, }); } } catch (e: any) { - props.dispatch(setAppMessage(new AppMessage(e.message))); toast({ title: TOAST_TITLE_ERROR, description: e.message, @@ -614,7 +621,11 @@ const Settings = (props: SettingsProps) => { ), ); } catch (e: any) { - props.dispatch(setAppMessage(new AppMessage(e.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: e.message, + variant: "destructive", + }); } finally { props.dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/users/details.tsx b/apps/web/components/admin/users/details.tsx index 4415916ae..0f8f0d54f 100644 --- a/apps/web/components/admin/users/details.tsx +++ b/apps/web/components/admin/users/details.tsx @@ -8,9 +8,9 @@ import { USER_EMAIL_SUBHEADER, USER_NAME_SUBHEADER, USER_TAGS_SUBHEADER, + TOAST_TITLE_ERROR, } from "../../../ui-config/strings"; import { FetchBuilder } from "@courselit/utils"; -import { AppMessage } from "@courselit/common-models"; import PermissionsEditor from "./permissions-editor"; import type { Address, UserWithAdminFields } from "@courselit/common-models"; import type { AppDispatch, AppState } from "@courselit/state-management"; @@ -21,10 +21,11 @@ import { Switch, Breadcrumbs, ComboBox, + useToast, } from "@courselit/components-library"; import { useCallback } from "react"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface DetailsProps { userId: string; @@ -36,6 +37,7 @@ const Details = ({ userId, address, dispatch }: DetailsProps) => { const [userData, setUserData] = useState(); const [enrolledCourses, setEnrolledCourses] = useState([]); const [tags, setTags] = useState([]); + const { toast } = useToast(); useEffect(() => { getUserDetails(); @@ -100,7 +102,11 @@ const Details = ({ userId, address, dispatch }: DetailsProps) => { setUserData(response.user); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -160,7 +166,11 @@ const Details = ({ userId, address, dispatch }: DetailsProps) => { setUserData(response.user); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -201,7 +211,11 @@ const Details = ({ userId, address, dispatch }: DetailsProps) => { setUserData(response.user); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/users/filter-container/filter-editor/product.tsx b/apps/web/components/admin/users/filter-container/filter-editor/product.tsx index f201727de..e2520720b 100644 --- a/apps/web/components/admin/users/filter-container/filter-editor/product.tsx +++ b/apps/web/components/admin/users/filter-container/filter-editor/product.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback, useMemo } from "react"; import { FetchBuilder } from "@courselit/utils"; import { + TOAST_TITLE_ERROR, POPUP_CANCEL_ACTION, USER_FILTER_APPLY_BTN, USER_FILTER_CATEGORY_PRODUCT, @@ -15,10 +16,9 @@ import { Form, FormSubmit, Select, + useToast, } from "@courselit/components-library"; -import { Address, AppMessage, Course } from "@courselit/common-models"; -import { actionCreators } from "@courselit/state-management"; -const { setAppMessage } = actionCreators; +import { Address, Course } from "@courselit/common-models"; interface ProductFilterEditorProps { onApply: (...args: any[]) => any; @@ -36,6 +36,7 @@ export default function ProductFilterEditor({ const [products, setProducts] = useState< Pick[] >([]); + const { toast } = useToast(); const loadCreatorCourses = useCallback(async () => { const query = ` @@ -58,7 +59,11 @@ export default function ProductFilterEditor({ setProducts([...response.courses]); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }, [address.backend, dispatch]); diff --git a/apps/web/components/admin/users/filter-container/filter-editor/tagged.tsx b/apps/web/components/admin/users/filter-container/filter-editor/tagged.tsx index fca8b27c2..de92d956e 100644 --- a/apps/web/components/admin/users/filter-container/filter-editor/tagged.tsx +++ b/apps/web/components/admin/users/filter-container/filter-editor/tagged.tsx @@ -1,13 +1,15 @@ -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Button, Form, FormSubmit, Select, + useToast, } from "@courselit/components-library"; import { AppDispatch } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; import { + TOAST_TITLE_ERROR, POPUP_CANCEL_ACTION, USER_FILTER_APPLY_BTN, USER_FILTER_CATEGORY_TAGGED, @@ -19,9 +21,7 @@ import React, { useState } from "react"; import { useCallback } from "react"; import { useMemo } from "react"; import PopoverHeader from "../popover-header"; -import { actionCreators } from "@courselit/state-management"; import { useEffect } from "react"; -const { setAppMessage } = actionCreators; interface TaggedFilterEditorProps { onApply: (...args: any[]) => any; @@ -37,6 +37,7 @@ export default function TaggedFilterEditor({ const [condition, setCondition] = useState(USER_FILTER_PRODUCT_HAS); const [value, setValue] = useState(""); const [tags, setTags] = useState([]); + const { toast } = useToast(); const getTags = useCallback(async () => { const query = ` @@ -55,7 +56,11 @@ export default function TaggedFilterEditor({ setTags(response.tags); } } catch (err) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } }, [address.backend, dispatch]); diff --git a/apps/web/components/admin/users/filter-container/filter-save.tsx b/apps/web/components/admin/users/filter-container/filter-save.tsx index 9e8944f26..8f11235ae 100644 --- a/apps/web/components/admin/users/filter-container/filter-save.tsx +++ b/apps/web/components/admin/users/filter-container/filter-save.tsx @@ -1,8 +1,14 @@ import React, { useState, ChangeEvent } from "react"; -import { Form, FormField, FormSubmit } from "@courselit/components-library"; +import { + Form, + FormField, + FormSubmit, + useToast, +} from "@courselit/components-library"; import Segment from "@ui-models/segment"; import { BUTTON_SAVE, + TOAST_TITLE_ERROR, USER_FILTER_NEW_SEGMENT_NAME, USER_FILTER_SAVE_DESCRIPTION, } from "@ui-config/strings"; @@ -11,7 +17,6 @@ import { FetchBuilder } from "@courselit/utils"; import type { AppDispatch, AppState } from "@courselit/state-management"; import { Address, - AppMessage, UserFilter, UserFilterAggregator, } from "@courselit/common-models"; @@ -20,7 +25,7 @@ import { actionCreators } from "@courselit/state-management"; import type { AnyAction } from "redux"; import PopoverDescription from "./popover-description"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface FilterSaveProps { filters: UserFilter[]; @@ -38,6 +43,7 @@ export default function FilterSave({ dismissPopover, }: FilterSaveProps) { const [name, setName] = useState(""); + const { toast } = useToast(); const onSubmit = async (e: FormEvent) => { e.preventDefault(); @@ -84,7 +90,11 @@ export default function FilterSave({ dismissPopover(); } } catch (err) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && (dispatch as ThunkDispatch)( diff --git a/apps/web/components/admin/users/filter-container/index.tsx b/apps/web/components/admin/users/filter-container/index.tsx index 17d3999a2..8b149b3a2 100644 --- a/apps/web/components/admin/users/filter-container/index.tsx +++ b/apps/web/components/admin/users/filter-container/index.tsx @@ -6,12 +6,14 @@ import { IconButton, Popover, Select, + useToast, } from "@courselit/components-library"; import { AppDispatch, AppState } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; import { useState } from "react"; import { ThunkDispatch } from "redux-thunk"; import { + TOAST_TITLE_ERROR, USER_FILTER_AGGREGATOR_ALL, USER_FILTER_AGGREGATOR_ANY, USER_FILTER_AGGREGATOR_HEADER, @@ -25,7 +27,6 @@ import SegmentEditor from "./segment-editor"; import { AnyAction } from "redux"; import { Address, - AppMessage, State, UserFilter, UserFilterAggregator, @@ -39,7 +40,7 @@ import AppLoader from "@components/app-loader"; const FilterChip = dynamic(() => import("./filter-chip")); const FilterSave = dynamic(() => import("./filter-save")); const FilterEditor = dynamic(() => import("./filter-editor")); -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface FilterContainerProps { onChange: ({ @@ -69,6 +70,8 @@ export default function FilterContainer({ const [internalFilters, setInternalFilters] = useState( filter?.filters || [], ); + const { toast } = useToast(); + const defaultSegment: Segment = useMemo( () => ({ name: USER_FILTER_LABEL_DEFAULT, @@ -132,7 +135,11 @@ export default function FilterContainer({ mapSegments(response.segments); } } catch (err) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && (dispatch as ThunkDispatch)( @@ -184,7 +191,11 @@ export default function FilterContainer({ setCount(response.count); } } catch (err) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { setCountLoading(false); } diff --git a/apps/web/components/admin/users/filter-container/segment-editor.tsx b/apps/web/components/admin/users/filter-container/segment-editor.tsx index 45f5de755..883196c53 100644 --- a/apps/web/components/admin/users/filter-container/segment-editor.tsx +++ b/apps/web/components/admin/users/filter-container/segment-editor.tsx @@ -1,12 +1,17 @@ import type { Address } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; -import { Button, IconButton, ScrollArea } from "@courselit/components-library"; +import { + Button, + IconButton, + ScrollArea, + useToast, +} from "@courselit/components-library"; import { Delete } from "@courselit/icons"; import type { AppDispatch, AppState } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; import React, { useState } from "react"; import type { ThunkDispatch } from "redux-thunk"; import { + TOAST_TITLE_ERROR, POPUP_CANCEL_ACTION, POPUP_OK_ACTION, USER_DELETE_SEGMENT, @@ -20,7 +25,7 @@ import PopoverHeader from "./popover-header"; import type { AnyAction } from "redux"; import { actionCreators } from "@courselit/state-management"; import DocumentationLink from "@components/public/documentation-link"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface DismissPopoverProps { selectedSegment: string; @@ -44,6 +49,7 @@ export default function SegmentEditor({ dismissPopover, }: SegmentEditorProps) { const [activeSegment, setActiveSegment] = useState(); + const { toast } = useToast(); const deleteSegment = async () => { const mutation = ` @@ -91,7 +97,11 @@ export default function SegmentEditor({ }); } } catch (err) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && (dispatch as ThunkDispatch)( diff --git a/apps/web/components/admin/users/index.tsx b/apps/web/components/admin/users/index.tsx index 7d6f66d96..f9cf1b724 100644 --- a/apps/web/components/admin/users/index.tsx +++ b/apps/web/components/admin/users/index.tsx @@ -5,6 +5,7 @@ import { USERS_MANAGER_PAGE_HEADING, USER_TABLE_HEADER_LAST_ACTIVE, BTN_MANAGE_TAGS, + TOAST_TITLE_ERROR, } from "../../../ui-config/strings"; import { FetchBuilder } from "@courselit/utils"; import { connect } from "react-redux"; @@ -14,7 +15,6 @@ import { User, Address, State, - AppMessage, UserFilter, UserFilterAggregator, } from "@courselit/common-models"; @@ -30,12 +30,13 @@ import { Avatar, AvatarFallback, AvatarImage, + useToast, } from "@courselit/components-library"; import { formattedLocaleDate } from "@ui-lib/utils"; import FilterContainer from "./filter-container"; import { useCallback } from "react"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface UserManagerProps { address: Address; @@ -51,6 +52,7 @@ export const Users = ({ address, dispatch, loading }: UserManagerProps) => { const [filtersAggregator, setFiltersAggregator] = useState("or"); const [count, setCount] = useState(0); + const { toast } = useToast(); /* const handleRowsPerPageChange = ( @@ -149,7 +151,11 @@ export const Users = ({ address, dispatch, loading }: UserManagerProps) => { setCount(response.count); } } catch (err) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { (dispatch as ThunkDispatch)( networkAction(false), diff --git a/apps/web/components/admin/users/permissions-editor.tsx b/apps/web/components/admin/users/permissions-editor.tsx index c4d734ae1..7e607c210 100644 --- a/apps/web/components/admin/users/permissions-editor.tsx +++ b/apps/web/components/admin/users/permissions-editor.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import { + TOAST_TITLE_ERROR, PERM_SECTION_HEADER, USER_PERMISSION_AREA_SUBTEXT, } from "@ui-config/strings"; @@ -7,14 +8,15 @@ import { connect } from "react-redux"; import { FetchBuilder } from "@courselit/utils"; import type { AppDispatch, AppState } from "@courselit/state-management"; import { actionCreators } from "@courselit/state-management"; -import { AppMessage } from "@courselit/common-models"; -import type { User, Address } from "@courselit/common-models"; -import { Checkbox } from "@courselit/components-library"; +import type { User, Address, State } from "@courselit/common-models"; +import { Checkbox, useToast } from "@courselit/components-library"; import { Section } from "@courselit/components-library"; import permissionToCaptionMap from "./permissions-to-caption-map"; import DocumentationLink from "@components/public/documentation-link"; +import { ThunkDispatch } from "redux-thunk"; +import { AnyAction } from "redux"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface PermissionsEditorProps { user: User; @@ -30,6 +32,7 @@ export function PermissionsEditor({ networkAction: networkCallUnderway, }: PermissionsEditorProps) { const [activePermissions, setActivePermissions] = useState([]); + const { toast } = useToast(); useEffect(() => { setActivePermissions(user.permissions); @@ -72,10 +75,11 @@ export function PermissionsEditor({ setActivePermissions(response.user.permissions); } } catch (err: any) { - dispatch && - (dispatch as ThunkDispatch)( - setAppMessage(new AppMessage(err.message)), - ); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && (dispatch as ThunkDispatch)( diff --git a/apps/web/components/admin/users/tags/index.tsx b/apps/web/components/admin/users/tags/index.tsx index 3f32423e5..10d6159d3 100644 --- a/apps/web/components/admin/users/tags/index.tsx +++ b/apps/web/components/admin/users/tags/index.tsx @@ -8,12 +8,14 @@ import { TableBody, TableHead, TableRow, + useToast, } from "@courselit/components-library"; import { AppDispatch } from "@courselit/state-management"; import { BTN_NEW_TAG, DELETE_TAG_POPUP_DESC, DELETE_TAG_POPUP_HEADER, + TOAST_TITLE_ERROR, PRODUCTS_TABLE_HEADER_ACTIONS, TAGS_TABLE_CONTEXT_MENU_DELETE_PRODUCT, TAGS_TABLE_CONTEXT_MENU_UNTAG, @@ -28,12 +30,12 @@ import { useCallback } from "react"; import { useEffect } from "react"; import { actionCreators } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { useState } from "react"; import { MoreVert } from "@courselit/icons"; import { usePathname } from "next/navigation"; import clsx from "clsx"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface TagsProps { address: Address; @@ -50,6 +52,7 @@ export default function Tags({ address, dispatch, prefix }: TagsProps) { const [tags, setTags] = useState([]); const [loading, setLoading] = useState(false); const path = usePathname(); + const { toast } = useToast(); const getTags = useCallback(async () => { const query = ` @@ -109,7 +112,11 @@ export default function Tags({ address, dispatch, prefix }: TagsProps) { setTags(response.tags); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } @@ -141,7 +148,11 @@ export default function Tags({ address, dispatch, prefix }: TagsProps) { setTags(response.tags); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch && dispatch(networkAction(false)); } diff --git a/apps/web/components/admin/users/tags/new.tsx b/apps/web/components/admin/users/tags/new.tsx index e8897870d..8325b8d9d 100644 --- a/apps/web/components/admin/users/tags/new.tsx +++ b/apps/web/components/admin/users/tags/new.tsx @@ -1,17 +1,19 @@ import React, { useState, ChangeEvent } from "react"; -import { Address, AppMessage } from "@courselit/common-models"; +import { Address } from "@courselit/common-models"; import { Breadcrumbs, Button, Form, FormField, Link, + useToast, } from "@courselit/components-library"; import { AppDispatch, AppState } from "@courselit/state-management"; import { BTN_CONTINUE, BTN_NEW_TAG, BUTTON_CANCEL_TEXT, + TOAST_TITLE_ERROR, USERS_MANAGER_PAGE_HEADING, USERS_TAG_HEADER, } from "@ui-config/strings"; @@ -20,7 +22,7 @@ import { FetchBuilder } from "@courselit/utils"; import { actionCreators } from "@courselit/state-management"; import { FormEvent } from "react"; import { usePathname, useRouter } from "next/navigation"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface NewTagProps { address: Address; @@ -32,6 +34,7 @@ export function NewTag({ address, dispatch }: NewTagProps) { const [loading, setLoading] = useState(false); const router = useRouter(); const path = usePathname(); + const { toast } = useToast(); const createTag = async (e: FormEvent) => { e.preventDefault(); @@ -65,7 +68,11 @@ export function NewTag({ address, dispatch }: NewTagProps) { ); } } catch (err: any) { - dispatch && dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { setLoading(false); dispatch && dispatch(networkAction(false)); diff --git a/apps/web/components/app-toast.tsx b/apps/web/components/app-toast.tsx deleted file mode 100644 index aa74260b9..000000000 --- a/apps/web/components/app-toast.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from "react"; -import { connect } from "react-redux"; -import { actionCreators } from "@courselit/state-management"; -import type { AppDispatch, AppState } from "@courselit/state-management"; -import { Toast } from "@courselit/components-library"; -import { Message } from "@courselit/common-models"; - -const { clearAppMessage } = actionCreators; - -interface AppToastProps { - message: Message; - dispatch: any; -} - -export const AppToast = (props: AppToastProps) => { - const { message, dispatch } = props; - - /* - const handleClose: any = (_: Event | SyntheticEvent, reason: string) => { - if (reason === "clickaway") { - return; - } - - props.dispatch(clearAppMessage()); - }; - - const getActionButtonsArray = () => { - const actionButtonsArray = [ - - - , - ]; - if (action) { - actionButtonsArray.unshift( - , - ); - } - - return actionButtonsArray; - }; - */ - return ( - - ); -}; - -const mapStateToProps = (state: AppState) => ({ - message: state.message, -}); - -const mapDispatchToProps = (dispatch: AppDispatch) => ({ - dispatch: dispatch, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(AppToast); diff --git a/apps/web/components/public/base-layout/template/index.tsx b/apps/web/components/public/base-layout/template/index.tsx index a4f626b69..0c1bf4f10 100644 --- a/apps/web/components/public/base-layout/template/index.tsx +++ b/apps/web/components/public/base-layout/template/index.tsx @@ -1,10 +1,9 @@ import React, { ReactNode } from "react"; import WidgetByName from "./widget-by-name"; -import { AppToast } from "../../../app-toast"; import { WidgetInstance } from "@courselit/common-models"; import { Footer, Header } from "@courselit/common-widgets"; import { ArrowDownward, ArrowUpward } from "@courselit/icons"; -import { Button } from "@courselit/components-library"; +import { Button, Toaster } from "@courselit/components-library"; import { AppDispatch, AppState } from "@courselit/state-management"; interface TemplateProps { @@ -206,9 +205,7 @@ const Template = (props: TemplateProps) => { state={state} /> )} - {state.message && dispatch && ( - - )} +
); }; diff --git a/apps/web/components/public/checkout/free.tsx b/apps/web/components/public/checkout/free.tsx index 44c903bda..0ed72b32b 100644 --- a/apps/web/components/public/checkout/free.tsx +++ b/apps/web/components/public/checkout/free.tsx @@ -1,16 +1,18 @@ import React, { useState } from "react"; -import { ENROLL_BUTTON_TEXT } from "../../../ui-config/strings"; +import { + ENROLL_BUTTON_TEXT, + TOAST_TITLE_ERROR, +} from "../../../ui-config/strings"; import { connect } from "react-redux"; import { useRouter } from "next/router"; import { actionCreators } from "@courselit/state-management"; import type { Address, Course } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; import type { AppDispatch, AppState } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; import { refreshUserProfile } from "@courselit/state-management/dist/action-creators"; -import { Button2 } from "@courselit/components-library"; +import { Button2, useToast } from "@courselit/components-library"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface FreeProps { course: Course; @@ -21,6 +23,7 @@ interface FreeProps { const Free = ({ course, dispatch, address }: FreeProps) => { const router = useRouter(); const [disabled, setDisabled] = useState(false); + const { toast } = useToast(); const handleClick = async () => { const payload = { @@ -46,10 +49,18 @@ const Free = ({ course, dispatch, address }: FreeProps) => { dispatch(refreshUserProfile()); router.replace(`/my-content`); } else if (response.status === "failed") { - dispatch(setAppMessage(new AppMessage(response.error))); + toast({ + title: TOAST_TITLE_ERROR, + description: response.error, + variant: "destructive", + }); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); setDisabled(false); diff --git a/apps/web/components/public/checkout/razorpay.tsx b/apps/web/components/public/checkout/razorpay.tsx index 19766abc4..c8c91d58b 100644 --- a/apps/web/components/public/checkout/razorpay.tsx +++ b/apps/web/components/public/checkout/razorpay.tsx @@ -1,21 +1,18 @@ import React from "react"; -import { Button2 } from "@courselit/components-library"; -import { ENROLL_BUTTON_TEXT } from "../../../ui-config/strings"; +import { Button2, useToast } from "@courselit/components-library"; +import { + ENROLL_BUTTON_TEXT, + TOAST_TITLE_ERROR, +} from "../../../ui-config/strings"; import { connect } from "react-redux"; import { useRouter } from "next/router"; import type { AppState, AppDispatch } from "@courselit/state-management"; -import { - Address, - AppMessage, - Course, - Profile, - SiteInfo, -} from "@courselit/common-models"; +import { Address, Course, Profile, SiteInfo } from "@courselit/common-models"; import { FetchBuilder } from "@courselit/utils"; import { actionCreators } from "@courselit/state-management"; import Script from "next/script"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface RazorpayProps { course: Course; @@ -28,6 +25,7 @@ interface RazorpayProps { const RazorpayComp = (props: RazorpayProps) => { const { course, siteInfo, address, dispatch, profile } = props; const router = useRouter(); + const { toast } = useToast(); const verifySignature = async (response) => { const fetch = new FetchBuilder() @@ -54,7 +52,11 @@ const RazorpayComp = (props: RazorpayProps) => { `/checkout/${course.courseId}?id=${verifyResponse.purchaseId}&source=/course/${course.slug}/${course.courseId}`, ); } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -102,7 +104,11 @@ const RazorpayComp = (props: RazorpayProps) => { router.replace(`/course/${course.slug}/${course.courseId}`); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } diff --git a/apps/web/components/public/checkout/stripe.tsx b/apps/web/components/public/checkout/stripe.tsx index 856940e75..1c73b0e19 100644 --- a/apps/web/components/public/checkout/stripe.tsx +++ b/apps/web/components/public/checkout/stripe.tsx @@ -1,20 +1,18 @@ import React from "react"; -import { Button2 } from "@courselit/components-library"; +import { Button2, useToast } from "@courselit/components-library"; import { loadStripe } from "@stripe/stripe-js"; -import { ENROLL_BUTTON_TEXT } from "../../../ui-config/strings"; +import { + ENROLL_BUTTON_TEXT, + TOAST_TITLE_ERROR, +} from "../../../ui-config/strings"; import { connect } from "react-redux"; import { useRouter } from "next/router"; import type { AppState, AppDispatch } from "@courselit/state-management"; -import { - Address, - AppMessage, - Course, - SiteInfo, -} from "@courselit/common-models"; +import { Address, Course, SiteInfo } from "@courselit/common-models"; import { FetchBuilder } from "@courselit/utils"; import { actionCreators } from "@courselit/state-management"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; interface StripeProps { course: Course; @@ -27,6 +25,7 @@ const Stripe = (props: StripeProps) => { const { course, siteInfo, address, dispatch } = props; const stripePromise = loadStripe(siteInfo.stripeKey as string); const router = useRouter(); + const { toast } = useToast(); const handleClick = async () => { const payload = { @@ -60,7 +59,11 @@ const Stripe = (props: StripeProps) => { router.replace(`/course/${course.slug}/${course.courseId}`); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -90,4 +93,4 @@ const mapStateToProps = (state: AppState) => ({ const mapDispatchToProps = (dispatch: AppDispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Stripe); +export default connect(mapStateToProps, mapDispatchToProps)(Stripe); diff --git a/apps/web/components/public/lesson-viewer/index.tsx b/apps/web/components/public/lesson-viewer/index.tsx index 1d7e65f30..e30f9ff42 100644 --- a/apps/web/components/public/lesson-viewer/index.tsx +++ b/apps/web/components/public/lesson-viewer/index.tsx @@ -17,6 +17,7 @@ import { COURSE_PROGRESS_NEXT, COURSE_PROGRESS_PREV, ENROLL_BUTTON_TEXT, + TOAST_TITLE_ERROR, NOT_ENROLLED_HEADER, } from "../../../ui-config/strings"; import { @@ -24,6 +25,7 @@ import { Link, Button2, Skeleton, + useToast, } from "@courselit/components-library"; import type { Address, @@ -32,13 +34,9 @@ import type { Quiz, SiteInfo, } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; import type { AppDispatch, AppState } from "@courselit/state-management"; import { useRouter } from "next/router"; -import { - refreshUserProfile, - setAppMessage, -} from "@courselit/state-management/dist/action-creators"; +import { refreshUserProfile } from "@courselit/state-management/dist/action-creators"; import { ArrowLeft, ArrowRight, ArrowDownward } from "@courselit/icons"; import { isEnrolled } from "../../../ui-lib/utils"; import LessonEmbedViewer from "./embed-viewer"; @@ -86,6 +84,7 @@ const LessonViewer = ({ const [lesson, setLesson] = useState(); const [error, setError] = useState(); const router = useRouter(); + const { toast } = useToast(); useEffect(() => { if (status === "authenticated") { @@ -176,7 +175,11 @@ const LessonViewer = ({ } } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } diff --git a/apps/web/components/public/lesson-viewer/quiz-viewer.tsx b/apps/web/components/public/lesson-viewer/quiz-viewer.tsx index ef69a459d..3e69cce67 100644 --- a/apps/web/components/public/lesson-viewer/quiz-viewer.tsx +++ b/apps/web/components/public/lesson-viewer/quiz-viewer.tsx @@ -1,6 +1,5 @@ import { Address, - AppMessage, Question, Quiz as QuizViewer, } from "@courselit/common-models"; @@ -9,17 +8,18 @@ import { AppDispatch, AppState, } from "@courselit/state-management"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { ChangeEvent, useState } from "react"; import { connect } from "react-redux"; import { + TOAST_TITLE_ERROR, QUIZ_FAIL_MESSAGE, QUIZ_PASS_MESSAGE, QUIZ_VIEWER_EVALUATE_BTN, QUIZ_VIEWER_EVALUATE_BTN_LOADING, + TOAST_TITLE_SUCCESS, } from "../../../ui-config/strings"; -import { Form, FormSubmit } from "@courselit/components-library"; +import { Form, FormSubmit, useToast } from "@courselit/components-library"; const { networkAction } = actionCreators; @@ -36,6 +36,7 @@ function QuizViewer({ content, lessonId, dispatch, address }: QuizViewerProps) { ...content.questions.map((item) => []), ]); const [loading, setLoading] = useState(false); + const { toast } = useToast(); const setAnswerForQuestion = ( checked: boolean, @@ -98,25 +99,24 @@ function QuizViewer({ content, lessonId, dispatch, address }: QuizViewerProps) { if (response.result) { const { pass, score, passingGrade } = response.result; if (pass) { - dispatch( - setAppMessage( - new AppMessage( - `${QUIZ_PASS_MESSAGE} ${score} points.`, - ), - ), - ); + toast({ + title: TOAST_TITLE_SUCCESS, + description: `${QUIZ_PASS_MESSAGE} ${score} points.`, + }); } else { - dispatch( - setAppMessage( - new AppMessage( - `${QUIZ_FAIL_MESSAGE} ${score} points. Requires ${passingGrade} points.`, - ), - ), - ); + toast({ + title: TOAST_TITLE_ERROR, + description: `${QUIZ_FAIL_MESSAGE} ${score} points. Requires ${passingGrade} points.`, + variant: "destructive", + }); } } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); setLoading(false); diff --git a/apps/web/components/public/purchase-status.tsx b/apps/web/components/public/purchase-status.tsx index 17be3f1b6..abac3e3a2 100644 --- a/apps/web/components/public/purchase-status.tsx +++ b/apps/web/components/public/purchase-status.tsx @@ -15,16 +15,17 @@ import { VERIFY_PAYMENT_BUTTON, VISIT_COURSE_BUTTON, PURCHASE_ID_HEADER, + TOAST_TITLE_ERROR, } from "../../ui-config/strings"; import dynamic from "next/dynamic"; import type { AppDispatch, AppState } from "@courselit/state-management"; -import { Address, AppMessage, Auth } from "@courselit/common-models"; +import { Address, Auth } from "@courselit/common-models"; import { FetchBuilder } from "@courselit/utils"; import { actionCreators } from "@courselit/state-management"; -import { Button, Button2 } from "@courselit/components-library"; +import { Button, Button2, useToast } from "@courselit/components-library"; import Link from "next/link"; -const { networkAction, setAppMessage } = actionCreators; +const { networkAction } = actionCreators; const AppLoader = dynamic(() => import("../app-loader")); @@ -42,6 +43,7 @@ const PurchaseStatus = (props: PurchaseStatusProps) => { const { id, source } = router.query; const courseLink: string = (source as string) || ""; const { dispatch, address } = props; + const { toast } = useToast(); useEffect(() => { if (props.auth.checked && props.auth.guest) { @@ -69,7 +71,11 @@ const PurchaseStatus = (props: PurchaseStatusProps) => { const response = await fetch.exec(); setStatus(response.status); } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } diff --git a/apps/web/components/public/scaffold.tsx b/apps/web/components/public/scaffold.tsx index ab7685651..b445ac8df 100644 --- a/apps/web/components/public/scaffold.tsx +++ b/apps/web/components/public/scaffold.tsx @@ -3,8 +3,7 @@ import Header from "./base-layout/header"; import { connect } from "react-redux"; import { useRouter } from "next/router"; import { AppDispatch, AppState } from "@courselit/state-management"; -import { Chip, Link, Modal } from "@courselit/components-library"; -import { AppToast } from "@components/app-toast"; +import { Chip, Link, Modal, Toaster } from "@courselit/components-library"; import { Message, SiteInfo } from "@courselit/common-models"; export interface ComponentScaffoldMenuItem { @@ -125,9 +124,7 @@ const ComponentScaffold = ({ > {drawer} - {message && dispatch && ( - - )} + ); }; diff --git a/apps/web/pages/dashboard/page/[id]/edit.tsx b/apps/web/pages/dashboard/page/[id]/edit.tsx index 26568bc2d..0d22636b2 100644 --- a/apps/web/pages/dashboard/page/[id]/edit.tsx +++ b/apps/web/pages/dashboard/page/[id]/edit.tsx @@ -18,7 +18,7 @@ import { import { canAccessDashboard } from "@ui-lib/utils"; import { useSession } from "next-auth/react"; import AppLoader from "@components/app-loader"; -import { AppToast } from "@components/app-toast"; +import { Toaster } from "@courselit/components-library"; interface EditPageProps { address: Address; @@ -83,9 +83,7 @@ function EditPage({ prefix="/dashboard" state={state} /> - {message && dispatch && ( - - )} + ); } diff --git a/apps/web/pages/login.tsx b/apps/web/pages/login.tsx index 9a7c35566..7bf6d8035 100644 --- a/apps/web/pages/login.tsx +++ b/apps/web/pages/login.tsx @@ -10,18 +10,23 @@ import { LOGIN_FORM_DISCLAIMER, LOADING, LOGIN_SUCCESS, + TOAST_TITLE_ERROR, + TOAST_TITLE_SUCCESS, } from "../ui-config/strings"; import { useRouter } from "next/router"; import type { Address, Auth, State } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; import { connect } from "react-redux"; import { AppDispatch } from "@courselit/state-management"; import BaseLayout from "../components/public/base-layout"; import { getBackendAddress, getPage } from "../ui-lib/utils"; -import { Form, FormField, FormSubmit } from "@courselit/components-library"; +import { + Form, + FormField, + FormSubmit, + useToast, +} from "@courselit/components-library"; import { signIn } from "next-auth/react"; import { FormEvent } from "react"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import Link from "next/link"; import { useEffect } from "react"; @@ -44,6 +49,7 @@ const Login = ({ page, auth, dispatch }: LoginProps) => { const router = useRouter(); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); + const { toast } = useToast(); useEffect(() => { if (!auth.guest) { @@ -75,7 +81,11 @@ const Login = ({ page, auth, dispatch }: LoginProps) => { if (response.ok) { setShowCode(true); } else { - dispatch(setAppMessage(new AppMessage(resp.error))); + toast({ + title: TOAST_TITLE_ERROR, + description: resp.error, + variant: "destructive", + }); } } finally { setLoading(false); @@ -94,7 +104,10 @@ const Login = ({ page, auth, dispatch }: LoginProps) => { if (response?.error) { setError(`Can't sign you in at this time`); } else { - dispatch(setAppMessage(new AppMessage(LOGIN_SUCCESS))); + toast({ + title: TOAST_TITLE_SUCCESS, + description: LOGIN_SUCCESS, + }); } } finally { setLoading(false); diff --git a/apps/web/pages/profile/index.tsx b/apps/web/pages/profile/index.tsx index 0fcc83015..ba639ea96 100644 --- a/apps/web/pages/profile/index.tsx +++ b/apps/web/pages/profile/index.tsx @@ -13,6 +13,8 @@ import { PROFILE_SECTION_DISPLAY_PICTURE, MEDIA_SELECTOR_UPLOAD_BTN_CAPTION, MEDIA_SELECTOR_REMOVE_BTN_CAPTION, + TOAST_TITLE_ERROR, + TOAST_TITLE_SUCCESS, } from "../../ui-config/strings"; import { connect } from "react-redux"; import { actionCreators } from "@courselit/state-management"; @@ -29,6 +31,7 @@ import { Avatar, AvatarFallback, AvatarImage, + useToast, } from "@courselit/components-library"; import type { Address, @@ -38,7 +41,6 @@ import type { Profile, State, } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; import { AppDispatch } from "@courselit/state-management"; import BaseLayout from "../../components/public/base-layout"; import { useRouter } from "next/router"; @@ -67,8 +69,9 @@ function ProfileIndex({ useState>(); const [avatar, setAvatar] = useState>({}); const [subscribedToUpdates, setSubscribedToUpdates] = useState(false); - const { networkAction, refreshUserProfile, setAppMessage } = actionCreators; + const { networkAction, refreshUserProfile } = actionCreators; const router = useRouter(); + const { toast } = useToast(); useEffect(() => { if (auth.checked && auth.guest) { @@ -162,9 +165,16 @@ function ProfileIndex({ dispatch(networkAction(true)); await fetch.exec(); dispatch(refreshUserProfile()); - dispatch(setAppMessage(new AppMessage(APP_MESSAGE_CHANGES_SAVED))); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_CHANGES_SAVED, + }); } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -213,9 +223,16 @@ function ProfileIndex({ dispatch(networkAction(true)); await fetch.exec(); dispatch(refreshUserProfile()); - dispatch(setAppMessage(new AppMessage(APP_MESSAGE_CHANGES_SAVED))); + toast({ + title: TOAST_TITLE_SUCCESS, + description: APP_MESSAGE_CHANGES_SAVED, + }); } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } @@ -250,7 +267,11 @@ function ProfileIndex({ await fetch.exec(); } catch (err: any) { setSubscribedToUpdates(!state); - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: TOAST_TITLE_ERROR, + description: err.message, + variant: "destructive", + }); } finally { dispatch(networkAction(false)); } diff --git a/apps/web/ui-config/strings.ts b/apps/web/ui-config/strings.ts index 76c69f724..33ad1d5b6 100644 --- a/apps/web/ui-config/strings.ts +++ b/apps/web/ui-config/strings.ts @@ -177,7 +177,7 @@ export const DELETE_LESSON_POPUP_HEADER = "Delete lesson"; export const APP_MESSAGE_COURSE_DELETED = "Product deleted"; export const APP_MESSAGE_LESSON_DELETED = "Lesson deleted"; export const APP_MESSAGE_LESSON_SAVED = "Lesson details saved"; -export const APP_MESSAGE_COURSE_SAVED = "Course details saved"; +export const APP_MESSAGE_COURSE_SAVED = "Changes saved"; export const ENROLL_IN_THE_COURSE = "You need to be enrolled in the course to view this lesson."; export const NOT_ENROLLED_HEADER = "Content Locked"; @@ -235,7 +235,6 @@ export const SUBHEADER_THEME_ADD_THEME_INPUT_LABEL = "Theme Editor"; export const SUBHEADER_THEME_ADD_THEME_INPUT_PLACEHOLDER = "Paste valid JSON here"; export const BUTTON_GET_THEMES = "Get more themes"; -export const ERROR_SNACKBAR_PREFIX = "Error"; export const BUTTON_THEME_APPLY = "Apply"; export const BUTTON_THEME_UNINSTALL = "Uninstall"; export const BUTTON_THEME_INSTALL = "Install"; diff --git a/apps/web/ui-models/app-message.ts b/apps/web/ui-models/app-message.ts deleted file mode 100644 index 428594863..000000000 --- a/apps/web/ui-models/app-message.ts +++ /dev/null @@ -1,32 +0,0 @@ -interface AppMessageAction { - text: string; - cb: (...args: any[]) => void; -} - -class AppMessage { - public action?: AppMessageAction; - - constructor( - private message: string, - private actionText?: string, - private actionFunc?: (...args: any[]) => void, - ) { - if (actionText && typeof actionText !== "string") { - throw new Error("actionText should be of type string"); - } - - if (actionFunc && typeof actionFunc !== "function") { - throw new Error("actionText should be of type function"); - } - - this.message = message; - if (actionText && actionFunc) { - this.action = { - text: actionText, - cb: actionFunc, - }; - } - } -} - -export default AppMessage; diff --git a/packages/common-models/src/app-message.ts b/packages/common-models/src/app-message.ts deleted file mode 100644 index 222ab09ff..000000000 --- a/packages/common-models/src/app-message.ts +++ /dev/null @@ -1,32 +0,0 @@ -interface AppMessageAction { - text: string; - cb: (...args: unknown[]) => void; -} - -class AppMessage { - public action?: AppMessageAction; - - constructor( - private message: string, - private actionText?: string, - private actionFunc?: (...args: unknown[]) => void, - ) { - if (actionText && typeof actionText !== "string") { - throw new Error("actionText should be of type string"); - } - - if (actionFunc && typeof actionFunc !== "function") { - throw new Error("actionText should be of type function"); - } - - this.message = message; - if (actionText && actionFunc) { - this.action = { - text: actionText, - cb: actionFunc, - }; - } - } -} - -export default AppMessage; diff --git a/packages/common-models/src/index.ts b/packages/common-models/src/index.ts index 19e186733..caefc78de 100644 --- a/packages/common-models/src/index.ts +++ b/packages/common-models/src/index.ts @@ -1,4 +1,3 @@ -export { default as AppMessage } from "./app-message"; export { default as Message } from "./message"; export type { default as Address } from "./address"; export type { default as Auth } from "./auth"; diff --git a/packages/common-widgets/src/banner/widget.tsx b/packages/common-widgets/src/banner/widget.tsx index 4fb3bf143..9545ae3a6 100644 --- a/packages/common-widgets/src/banner/widget.tsx +++ b/packages/common-widgets/src/banner/widget.tsx @@ -1,7 +1,7 @@ "use client"; import { FormEvent, useState } from "react"; -import { AppMessage, Media, WidgetProps } from "@courselit/common-models"; +import { Media, WidgetProps } from "@courselit/common-models"; import { Image, PriceTag, @@ -10,9 +10,9 @@ import { FormField, Button2, Link, + useToast, } from "@courselit/components-library"; import { actionCreators } from "@courselit/state-management"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import { FetchBuilder } from "@courselit/utils"; import { DEFAULT_FAILURE_MESSAGE, DEFAULT_SUCCESS_MESSAGE } from "./constants"; import Settings from "./settings"; @@ -56,6 +56,7 @@ export default function Widget({ }: WidgetProps) { const [email, setEmail] = useState(""); const [success, setSuccess] = useState(false); + const { toast } = useToast(); const type = product.pageType; const defaultSuccessMessage: Record = { type: "doc", @@ -144,11 +145,11 @@ export default function Widget({ setSuccess(true); } } catch (e) { - dispatch( - setAppMessage( - new AppMessage(failureMessage || DEFAULT_FAILURE_MESSAGE), - ), - ); + toast({ + title: "Error", + description: failureMessage || DEFAULT_FAILURE_MESSAGE, + variant: "destructive", + }); } finally { dispatch(actionCreators.networkAction(false)); } diff --git a/packages/common-widgets/src/content/widget.tsx b/packages/common-widgets/src/content/widget.tsx index 1dfbad17a..6bd381f81 100644 --- a/packages/common-widgets/src/content/widget.tsx +++ b/packages/common-widgets/src/content/widget.tsx @@ -1,8 +1,7 @@ "use client"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { - AppMessage, Course, Group, Lesson, @@ -12,23 +11,23 @@ import { import Settings from "./settings"; import { FetchBuilder } from "@courselit/utils"; import { actionCreators } from "@courselit/state-management"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import { Link, Chip, LessonIcon, TextRenderer, Skeleton, + useToast, + Badge, + Accordion, + AccordionItem, + AccordionTrigger, + AccordionContent, } from "@courselit/components-library"; import { verticalPadding as defaultVerticalPadding, horizontalPadding as defaultHorizontalPadding, } from "./defaults"; -import { Badge } from "@courselit/components-library"; -import { Accordion } from "@courselit/components-library"; -import { AccordionItem } from "@courselit/components-library"; -import { AccordionTrigger } from "@courselit/components-library"; -import { AccordionContent } from "@courselit/components-library"; interface CourseWithGroups extends Course { groups: Group[]; @@ -56,6 +55,7 @@ export default function Widget({ const [formattedCourse, setFormattedCourse] = useState< Record >({}); + const { toast } = useToast(); useEffect(() => { if (product.courseId) { @@ -116,7 +116,11 @@ export default function Widget({ setCourse(response.course); } } catch (err: any) { - dispatch(setAppMessage(new AppMessage(err.message))); + toast({ + title: "Error", + description: err.message, + variant: "destructive", + }); } finally { dispatch(actionCreators.networkAction(false)); } diff --git a/packages/common-widgets/src/email-form/widget.tsx b/packages/common-widgets/src/email-form/widget.tsx index 9f8a34667..240d1f3a2 100644 --- a/packages/common-widgets/src/email-form/widget.tsx +++ b/packages/common-widgets/src/email-form/widget.tsx @@ -1,18 +1,22 @@ "use client"; -import React, { FormEvent, useState, useEffect } from "react"; -import { AppMessage, WidgetProps } from "@courselit/common-models"; +import { FormEvent, useState, useEffect } from "react"; +import { WidgetProps } from "@courselit/common-models"; import Settings from "./settings"; import { actionCreators } from "@courselit/state-management"; import { FetchBuilder } from "@courselit/utils"; -import { setAppMessage } from "@courselit/state-management/dist/action-creators"; import { DEFAULT_BTN_TEXT, DEFAULT_FAILURE_MESSAGE, DEFAULT_SUCCESS_MESSAGE, DEFAULT_TITLE, } from "./constants"; -import { Form, FormField, Button2 } from "@courselit/components-library"; +import { + Form, + FormField, + Button2, + useToast, +} from "@courselit/components-library"; import { verticalPadding as defaultVerticalPadding, horizontalPadding as defaultHorizontalPadding, @@ -45,6 +49,7 @@ const Widget = ({ const [turnstileToken, setTurnstileToken] = useState(""); const [errorMessage, setErrorMessage] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); + const { toast } = useToast(); const justifyContent = alignment === "center" @@ -99,23 +104,17 @@ const Widget = ({ dispatch(actionCreators.networkAction(true)); const response = await fetch.exec(); if (response.response) { - dispatch( - setAppMessage( - new AppMessage( - successMessage || DEFAULT_SUCCESS_MESSAGE, - ), - ), - ); + toast({ + title: "Success", + description: successMessage || DEFAULT_SUCCESS_MESSAGE, + }); setName(""); setEmail(""); } else { - dispatch( - setAppMessage( - new AppMessage( - failureMessage || DEFAULT_FAILURE_MESSAGE, - ), - ), - ); + toast({ + title: "Error", + description: failureMessage || DEFAULT_FAILURE_MESSAGE, + }); } } catch (e) { console.error(e.message); diff --git a/packages/state-management/src/action-creators.ts b/packages/state-management/src/action-creators.ts index d10f65056..7722c387f 100644 --- a/packages/state-management/src/action-creators.ts +++ b/packages/state-management/src/action-creators.ts @@ -9,8 +9,6 @@ import { PROFILE_CLEAR, SITEINFO_AVAILABLE, AUTH_CHECKED, - SET_MESSAGE, - CLEAR_MESSAGE, THEME_AVAILABLE, SET_ADDRESS, TYPEFACES_AVAILABLE, @@ -25,7 +23,6 @@ import type { Theme, Typeface, } from "@courselit/common-models"; -import { AppMessage } from "@courselit/common-models"; import { ThunkAction } from "redux-thunk"; import { AnyAction } from "redux"; import { ServerConfig } from "@courselit/common-models"; @@ -201,14 +198,6 @@ export function newSiteInfoAvailable(info: SiteInfo) { return { type: SITEINFO_AVAILABLE, siteinfo: info }; } -export function setAppMessage(message: AppMessage) { - return (dispatch: any) => dispatch({ type: SET_MESSAGE, message }); -} - -export function clearAppMessage() { - return (dispatch: any) => dispatch({ type: CLEAR_MESSAGE }); -} - export function themeAvailable(theme: Theme) { return { type: THEME_AVAILABLE, theme }; }