Skip to content

Commit

Permalink
Ported invite customer screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajat Saxena committed Oct 13, 2024
1 parent 8c822d3 commit 19be6b4
Show file tree
Hide file tree
Showing 33 changed files with 719 additions and 119 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
18 changes: 18 additions & 0 deletions apps/web/app/dashboard2/product/[id]/customer/new/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"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 (
<NewCustomer
courseId={id as string}
prefix="/dashboard2"
address={address}
/>
);
}
7 changes: 6 additions & 1 deletion apps/web/app/dashboard2/product/[id]/product-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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({
Expand All @@ -12,8 +13,12 @@ export default function ProductLayout({
children: ReactNode;
}) {
const address = useContext(AddressContext);
const path = usePathname();
const isNewCustomerAdditionScreen = path?.indexOf("/customer/new") !== -1;

return (
return isNewCustomerAdditionScreen ? (
children
) : (
<ProductEditorLayout prefix="/dashboard2" address={address} id={id}>
{children}
</ProductEditorLayout>
Expand Down
8 changes: 7 additions & 1 deletion apps/web/app/dashboard2/product/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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;
Expand All @@ -19,5 +20,10 @@ export default function Page({ children }: { children: ReactNode }) {
return <LoadingScreen />;
}

return children;
return (
<>
{children}
<Toaster />
</>
);
}
14 changes: 4 additions & 10 deletions apps/web/components/admin/products/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import {
PRODUCTS_TABLE_HEADER_TYPE,
} from "../../../ui-config/strings";
import { FetchBuilder } from "@courselit/utils";
import type { Address, Course, SiteInfo } from "@courselit/common-models";
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 from "./product";
import Product, { CourseDetails } from "./product";
import {
Link,
Button,
Expand Down Expand Up @@ -163,21 +163,15 @@ export const Index = ({ loading, address, dispatch, siteinfo }: IndexProps) => {
}}
>
{creatorCourses.map(
(
product: Course & {
published: boolean;
sales: number;
customers: number;
},
index: number,
) => (
(product: CourseDetails, index: number) => (
<Product
key={product.courseId}
details={product}
position={index}
onDelete={onDelete}
siteinfo={siteinfo}
address={address}
prefix={pathPrefix}
/>
),
)}
Expand Down
68 changes: 32 additions & 36 deletions apps/web/components/admin/products/new-customer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,44 @@ import { Address, AppMessage } from "@courselit/common-models";
import {
Form,
FormField,
Section,
Link,
Button,
ComboBox,
Breadcrumbs,
useToast,
} from "@courselit/components-library";
import { AppDispatch, AppState } from "@courselit/state-management";
import { AppDispatch } from "@courselit/state-management";
import { FetchBuilder } from "@courselit/utils";
import { connect } from "react-redux";
import {
BTN_GO_BACK,
BTN_INVITE,
PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER,
USER_TAGS_SUBHEADER,
} from "../../../ui-config/strings";
} from "@/ui-config/strings";
import {
networkAction,
setAppMessage,
} from "@courselit/state-management/dist/action-creators";
import useCourse from "./editor/course-hook";

interface NewCustomerProps {
address: Address;
dispatch: AppDispatch;
networkAction: boolean;
courseId: string;
prefix: string;
dispatch?: AppDispatch;
}

function NewCustomer({
export default function NewCustomer({
courseId,
address,
prefix,
dispatch,
networkAction: loading,
}: NewCustomerProps) {
const [email, setEmail] = useState("");
const [tags, setTags] = useState<string[]>([]);
const [systemTags, setSystemTags] = useState<string[]>([]);
const course = useCourse(courseId, address, dispatch);
const { toast } = useToast();

const getTags = useCallback(async () => {
const query = `
Expand All @@ -54,14 +56,14 @@ function NewCustomer({
.setIsGraphQLEndpoint(true)
.build();
try {
dispatch(networkAction(true));
dispatch && dispatch(networkAction(true));
const response = await fetch.exec();
if (response.tags) {
setSystemTags(response.tags);
}
} catch (err) {
} finally {
dispatch(networkAction(false));
dispatch && dispatch(networkAction(false));
}
}, [address.backend, dispatch]);

Expand Down Expand Up @@ -100,36 +102,39 @@ function NewCustomer({
.setIsGraphQLEndpoint(true)
.build();
try {
dispatch(networkAction(true));
dispatch && dispatch(networkAction(true));
const response = await fetch.exec();
if (response.user) {
setEmail("");
setTags([]);
dispatch(
setAppMessage(
new AppMessage(
`${response.user.email} has been invited.`,
),
),
);
const message = `${response.user.email} has been invited.`;
dispatch && dispatch(setAppMessage(new AppMessage(message)));
toast({
title: "Success",
description: message,
});
}
} catch (err: any) {
dispatch(setAppMessage(new AppMessage(err.message)));
dispatch && dispatch(setAppMessage(new AppMessage(err.message)));
toast({
title: "Error",
description: err.message,
});
} finally {
dispatch(networkAction(false));
dispatch && dispatch(networkAction(false));
}
};

return (
<div className="flex flex-col gap-4">
<Breadcrumbs aria-label="breakcrumb">
<Link href="/dashboard/products/">Products</Link>
<Link href={`/dashboard/product/${courseId}/reports`}>
Product
<Link href={`${prefix}/products/`}>Products</Link>
<Link href={`${prefix}/product/${courseId}/reports`}>
{course?.title || "..."}
</Link>
<p>{PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER}</p>
</Breadcrumbs>
<Section>
<>
<div className="flex flex-col">
<h1 className="text-4xl font-semibold mb-4">
{PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER}
Expand All @@ -146,7 +151,7 @@ function NewCustomer({
onChange={(e) => setEmail(e.target.value)}
/>
<div className="flex flex-col gap-2">
<p>{USER_TAGS_SUBHEADER}</p>
<h2>{USER_TAGS_SUBHEADER}</h2>
<ComboBox
key={
JSON.stringify(systemTags) +
Expand All @@ -166,22 +171,13 @@ function NewCustomer({
>
{BTN_INVITE}
</Button>
<Link href={`/dashboard/products`}>
<Link href={`${prefix}/products`}>
<Button variant="soft">{BTN_GO_BACK}</Button>
</Link>
</div>
</Form>
</div>
</Section>
</>
</div>
);
}

const mapStateToProps = (state: AppState) => ({
address: state.address,
networkAction: state.networkAction,
});

const mapDispatchToProps = (dispatch: AppDispatch) => ({ dispatch });

export default connect(mapStateToProps, mapDispatchToProps)(NewCustomer);
40 changes: 21 additions & 19 deletions apps/web/components/admin/products/product.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,32 @@ import {
} from "@courselit/components-library";
import { usePathname } from "next/navigation";

export type CourseDetails = Course & {
published: boolean;
sales: number;
customers: number;
pageId: string;
};

export default function Product({
details,
siteinfo,
address,
dispatch,
position,
onDelete,
prefix,
}: {
details: Course & {
published: boolean;
sales: number;
customers: number;
pageId: string;
};
details: CourseDetails;
siteinfo: SiteInfo;
address: Address;
dispatch: AppDispatch;
dispatch?: AppDispatch;
position: number;
onDelete: (position: number) => void;
prefix: string;
}) {
const product = details;
const path = usePathname();
const pathPrefix = path?.startsWith("/dashboard2")
? "/dashboard2"
: "/dashboard";

const deleteProduct = async () => {
const query = `
Expand All @@ -68,26 +69,27 @@ export default function Product({
.build();

try {
dispatch(networkAction(true));
dispatch && dispatch(networkAction(true));
const response = await fetch.exec();

if (response.result) {
onDelete(position);
}
} catch (err: any) {
dispatch(setAppMessage(new AppMessage(err.message)));
dispatch && dispatch(setAppMessage(new AppMessage(err.message)));
} finally {
dispatch(networkAction(false));
dispatch(setAppMessage(new AppMessage(APP_MESSAGE_COURSE_DELETED)));
dispatch && dispatch(networkAction(false));
dispatch &&
dispatch(
setAppMessage(new AppMessage(APP_MESSAGE_COURSE_DELETED)),
);
}
};

return (
<TableRow key={product.courseId}>
<td className="py-4">
<Link
href={`${pathPrefix}/product/${product.courseId}/reports`}
>
<Link href={`${prefix}/product/${product.courseId}/reports`}>
<p>{product.title}</p>
</Link>
</td>
Expand Down Expand Up @@ -123,7 +125,7 @@ export default function Product({
</MenuItem>
<MenuItem>
<Link
href={`/dashboard/page/${product.pageId}/edit?redirectTo=${pathPrefix}/products`}
href={`/dashboard/page/${product.pageId}/edit?redirectTo=${prefix}/products`}
className="flex w-full"
>
{PRODUCT_TABLE_CONTEXT_MENU_EDIT_PAGE}
Expand All @@ -132,7 +134,7 @@ export default function Product({
<div className="flex w-full border-b border-slate-200 my-1"></div>
<MenuItem>
<Link
href={`/dashboard/product/${product.courseId}/customer/new`}
href={`${prefix}/product/${product.courseId}/customer/new`}
>
{PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER}
</Link>
Expand Down
26 changes: 24 additions & 2 deletions apps/web/pages/dashboard/product/[id]/customer/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,41 @@ import React from "react";
import dynamic from "next/dynamic";
import { useRouter } from "next/router";
import { PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER } from "@ui-config/strings";
import { AppDispatch, AppState } from "@courselit/state-management";
import { connect } from "react-redux";
import { Address } from "@courselit/common-models";

const BaseLayout = dynamic(() => import("@components/admin/base-layout"));

const NewCustomer = dynamic(
() => import("@components/admin/products/new-customer"),
);

export default function New() {
function New({
address,
dispatch,
}: {
address: Address;
dispatch: AppDispatch;
}) {
const router = useRouter();
const { id } = router.query;
return (
<BaseLayout title={PRODUCT_TABLE_CONTEXT_MENU_INVITE_A_CUSTOMER}>
<NewCustomer courseId={id as string} />
<NewCustomer
courseId={id as string}
prefix="/dashboard"
address={address}
dispatch={dispatch}
/>
</BaseLayout>
);
}

const mapStateToProps = (state: AppState) => ({
address: state.address,
});

const mapDispatchToProps = (dispatch: AppDispatch) => ({ dispatch });

export default connect(mapStateToProps, mapDispatchToProps)(New);
Loading

0 comments on commit 19be6b4

Please sign in to comment.