From 6d43b24b85a6c9b432226b766b2b5d9b6cf66b6a Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 12:48:31 +0300 Subject: [PATCH 01/11] chore: draft PR --- apps/api/package.json | 1 + apps/api/src/queue.ts | 1 + yarn.lock | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/api/package.json b/apps/api/package.json index fe383525..759523af 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -17,6 +17,7 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", + "graphql-request": "^6.1.0", "helmet": "^7.1.0", "ioredis": "^5.3.2", "morgan": "^1.10.0", diff --git a/apps/api/src/queue.ts b/apps/api/src/queue.ts index 211a86ee..762cd7b1 100644 --- a/apps/api/src/queue.ts +++ b/apps/api/src/queue.ts @@ -2,6 +2,7 @@ import { Queue } from "bullmq"; import { connection } from "./lib/ioredis"; export enum Queues { + Business = "Business", Event = "Event", Mail = "Mail", Notification = "Notification", diff --git a/yarn.lock b/yarn.lock index 80e1e4be..e5356cf0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5145,7 +5145,7 @@ graphql-config@^5.0.2: string-env-interpolation "^1.0.1" tslib "^2.4.0" -graphql-request@^6.0.0: +graphql-request@^6.0.0, graphql-request@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== From 7b647bfb69d60aea031cec0314608ee1685c83c1 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 12:48:52 +0300 Subject: [PATCH 02/11] chore: yarn format --- apps/api/src/routers/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/routers/index.ts b/apps/api/src/routers/index.ts index bf7d93cc..ce55dcb4 100644 --- a/apps/api/src/routers/index.ts +++ b/apps/api/src/routers/index.ts @@ -6,6 +6,6 @@ import home from "./home"; const router = express.Router(); router.use("/api", api); -router.use("/", home) +router.use("/", home); export default router; From 742b161a8d67e510121ea61a3849ea56dce52528 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 16:30:53 +0300 Subject: [PATCH 03/11] feat: add business schema --- apps/api/package.json | 1 + .../businesses/operations/registerBusiness.ts | 28 +++++++++++++++++ apps/api/src/businesses/router.ts | 31 +++++++++++++++++++ apps/api/src/businesses/worker.ts | 0 apps/api/src/config.ts | 9 ++++-- apps/api/src/lib/graphql-request.ts | 12 +++++++ apps/api/src/lib/{webPush.ts => web-push.ts} | 16 +++++++--- apps/api/src/middleware/zodValidate.ts | 5 ++- apps/api/src/notifications/router.ts | 2 +- apps/api/src/orders/operations/initOrder.ts | 22 +++++++------ apps/api/src/orders/router.ts | 6 +--- apps/api/src/routers/api.ts | 6 ++-- packages/lib/graphql/graphql-request.ts | 21 +++++++++++++ packages/lib/graphql/queries/businesses.ts | 2 +- packages/lib/package.json | 6 +++- 15 files changed, 138 insertions(+), 29 deletions(-) create mode 100644 apps/api/src/businesses/operations/registerBusiness.ts create mode 100644 apps/api/src/businesses/router.ts create mode 100644 apps/api/src/businesses/worker.ts create mode 100644 apps/api/src/lib/graphql-request.ts rename apps/api/src/lib/{webPush.ts => web-push.ts} (51%) create mode 100644 packages/lib/graphql/graphql-request.ts diff --git a/apps/api/package.json b/apps/api/package.json index 759523af..be2eaea7 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -17,6 +17,7 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", + "graphql": "^16.8.1", "graphql-request": "^6.1.0", "helmet": "^7.1.0", "ioredis": "^5.3.2", diff --git a/apps/api/src/businesses/operations/registerBusiness.ts b/apps/api/src/businesses/operations/registerBusiness.ts new file mode 100644 index 00000000..2bb791af --- /dev/null +++ b/apps/api/src/businesses/operations/registerBusiness.ts @@ -0,0 +1,28 @@ +import { z } from "zod"; +import { gql } from "graphql-request"; + +import { client } from "../../lib/graphql-request"; + +const query = gql` + query getBusinesses { + business { + created_at + id + updated_at + name + } + } +`; + +export const businessSchema = z.object({ + name: z.string(), +}); + +export type BusinessAttributes = z.infer; + +export const registerBusiness = async (business: BusinessAttributes) => { + const data = await client.request(query); + console.log(business); + console.log(data); + return business; +}; diff --git a/apps/api/src/businesses/router.ts b/apps/api/src/businesses/router.ts new file mode 100644 index 00000000..b6027f35 --- /dev/null +++ b/apps/api/src/businesses/router.ts @@ -0,0 +1,31 @@ +import { NextFunction, Response, Router, Request } from "express"; +import { logger } from "../lib/winston"; +import { logRequest } from "../middleware/requestLogger"; +import { validate } from "../middleware/zodValidate"; +import { + registerBusiness, + businessSchema, +} from "./operations/registerBusiness"; + +const businessRouter = Router(); + +businessRouter.use(logRequest); + +// register a business +businessRouter.post( + "/", + validate(businessSchema), + async (req: Request, res: Response, next: NextFunction) => { + try { + // @ts-ignore + const business = await registerBusiness(req.body); + res.send({ + business, + }); + } catch (error) { + next(error); + } + } +); + +export default businessRouter; diff --git a/apps/api/src/businesses/worker.ts b/apps/api/src/businesses/worker.ts new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/src/config.ts b/apps/api/src/config.ts index 58d74489..15d81e9f 100644 --- a/apps/api/src/config.ts +++ b/apps/api/src/config.ts @@ -16,5 +16,10 @@ export const fromEmailAddress = process.env.FROM_EMAIL_ADDRESS || "emmanuelgatwech@gmail.com"; export const host = process.env.HOST || "localhost:3000"; -export const WebPushPublicVapidKey = process.env.WEB_PUSH_PUBLIC_VAPID_KEY; -export const WebPushPrivateVapidKey = process.env.WEB_PUSH_PRIVATE_VAPID_KEY; +export const WebPushPublicVapidKey = + process.env.WEB_PUSH_PUBLIC_VAPID_KEY || ""; +export const WebPushPrivateVapidKey = + process.env.WEB_PUSH_PRIVATE_VAPID_KEY || ""; + +export const hasuraEndpoint = process.env.HASURA_GRAPHQL_ENDPOINT || ""; +export const hasuraAdminSecret = process.env.HASURA_GRAPHQL_ADMIN_SECRET || ""; diff --git a/apps/api/src/lib/graphql-request.ts b/apps/api/src/lib/graphql-request.ts new file mode 100644 index 00000000..635447ca --- /dev/null +++ b/apps/api/src/lib/graphql-request.ts @@ -0,0 +1,12 @@ +import { graphQLClient } from "@sahil/lib/graphql/graphql-request"; +import { hasuraAdminSecret, hasuraEndpoint } from "../config"; + +const endpoint = hasuraEndpoint; + +export const client = graphQLClient(endpoint, { + headers: { + authorization: `Bearer MY_TOKEN`, + "x-hasura-admin-secret": hasuraAdminSecret, + "x-hasura-role": "user", + }, +}); diff --git a/apps/api/src/lib/webPush.ts b/apps/api/src/lib/web-push.ts similarity index 51% rename from apps/api/src/lib/webPush.ts rename to apps/api/src/lib/web-push.ts index dc8c0ed8..118af3fe 100644 --- a/apps/api/src/lib/webPush.ts +++ b/apps/api/src/lib/web-push.ts @@ -2,11 +2,17 @@ import { WebPushPrivateVapidKey, WebPushPublicVapidKey } from "../config"; const webPush = require("web-push"); -webPush.setVapidDetails( - "mailto:test@test.com", - WebPushPublicVapidKey, - WebPushPrivateVapidKey -); +export const setVapidKeys = () => { + if (WebPushPrivateVapidKey && WebPushPublicVapidKey) { + webPush.setVapidDetails( + "mailto:test@test.com", + WebPushPublicVapidKey, + WebPushPrivateVapidKey + ); + } +}; + +setVapidKeys(); export const sendPushNotification = (subscription: any, payload: any) => { return webPush.sendNotification(subscription, payload); diff --git a/apps/api/src/middleware/zodValidate.ts b/apps/api/src/middleware/zodValidate.ts index 40beee2c..3d8e77f3 100644 --- a/apps/api/src/middleware/zodValidate.ts +++ b/apps/api/src/middleware/zodValidate.ts @@ -23,8 +23,7 @@ export const validate = }; next(); - } catch (error) { - // @ts-ignore - return res.status(400).send(error.errors); + } catch (error: any) { + return res.status(400).json(error.errors); } }; diff --git a/apps/api/src/notifications/router.ts b/apps/api/src/notifications/router.ts index 1df64356..0d6e745a 100644 --- a/apps/api/src/notifications/router.ts +++ b/apps/api/src/notifications/router.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from "express"; -import { sendPushNotification } from "../lib/webPush"; +import { sendPushNotification } from "../lib/web-push"; const router = Router(); diff --git a/apps/api/src/orders/operations/initOrder.ts b/apps/api/src/orders/operations/initOrder.ts index 7a937379..f10cb9d2 100644 --- a/apps/api/src/orders/operations/initOrder.ts +++ b/apps/api/src/orders/operations/initOrder.ts @@ -1,12 +1,16 @@ -type OrderAttributes = { - created_at: Date; - customerId: string; - destination: string; - id: string; - orderId: string; - origin: string; - processedBy: string; -}; +import { z } from "zod"; + +export const orderSchema = z.object({ + orderId: z.string(), + created_at: z.date(), + customerId: z.string(), + destination: z.string(), + id: z.string(), + origin: z.string(), + processedBy: z.string(), +}); + +export type OrderAttributes = z.infer; export const initOrder = ( attributes: OrderAttributes diff --git a/apps/api/src/orders/router.ts b/apps/api/src/orders/router.ts index b79f5889..6687b9c2 100644 --- a/apps/api/src/orders/router.ts +++ b/apps/api/src/orders/router.ts @@ -4,15 +4,11 @@ import { object, z } from "zod"; import { logger } from "../lib/winston"; import { logRequest } from "../middleware/requestLogger"; import { validate } from "../middleware/zodValidate"; -import { initOrder } from "./operations/initOrder"; +import { initOrder, orderSchema } from "./operations/initOrder"; import { processOrder } from "./operations/processOrder"; const ordersRouter = Router(); -const orderSchema = z.object({ - orderId: z.string(), -}); - ordersRouter.use(logRequest); type OrdersActionType = { diff --git a/apps/api/src/routers/api.ts b/apps/api/src/routers/api.ts index 2088a7ca..c1d6836f 100644 --- a/apps/api/src/routers/api.ts +++ b/apps/api/src/routers/api.ts @@ -1,13 +1,15 @@ import { Router } from "express"; +import businesses from "../businesses/router"; +import notifications from "../notifications/router"; import orders from "../orders/router"; import users from "../users/router"; -import notifications from "../notifications/router"; const router = Router(); +router.use("/businesses", businesses); +router.use("/notifications", notifications); router.use("/orders", orders); router.use("/users", users); -router.use("/notifications", notifications); export default router; diff --git a/packages/lib/graphql/graphql-request.ts b/packages/lib/graphql/graphql-request.ts new file mode 100644 index 00000000..2341858a --- /dev/null +++ b/packages/lib/graphql/graphql-request.ts @@ -0,0 +1,21 @@ +import { request, gql } from "graphql-request"; +import { GraphQLClient } from "graphql-request"; + +type GraphQLClientOptions = { + headers?: { + authorization?: string; + "x-hasura-admin-secret"?: string; + "x-hasura-role"?: string; + }; +}; + +export const graphQLClient = ( + endpoint: string, + options: GraphQLClientOptions = {} +) => { + return new GraphQLClient(endpoint, { + headers: { + ...options.headers, + }, + }); +}; diff --git a/packages/lib/graphql/queries/businesses.ts b/packages/lib/graphql/queries/businesses.ts index eecec2a9..5a1befb7 100644 --- a/packages/lib/graphql/queries/businesses.ts +++ b/packages/lib/graphql/queries/businesses.ts @@ -1,7 +1,7 @@ import { gql } from "@apollo/client"; export const FETCH_BUSINESSES = gql` - query getClients { + query getBusinesses { business { created_at id diff --git a/packages/lib/package.json b/packages/lib/package.json index 039dfd4b..b7cd2a38 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -2,5 +2,9 @@ "name": "@sahil/lib", "version": "1.0.0", "main": "./index.ts", - "license": "MIT" + "license": "MIT", + "dependencies": { + "graphql": "^16.8.1", + "graphql-request": "^6.1.0" + } } From 01366cd25f8dc2cfa2851247b846c39235b15341 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 19:40:52 +0300 Subject: [PATCH 04/11] feat: validate and insert a new business --- .../BusinessRegistrationForm/AddressInfo.tsx | 38 ++++++- .../BusinessRegistrationForm/BusinessInfo.tsx | 9 ++ .../BusinessPreferencesInfo.tsx | 22 ++++ .../BusinessRegistrationForm/index.tsx | 1 + .../pages/businesses/register/[...step].tsx | 2 + apps/agent/tailwind.config.ts | 2 +- .../businesses/operations/registerBusiness.ts | 34 +++--- .../businesses/operations/verifyBusiness.ts | 1 + apps/api/src/businesses/router.ts | 16 ++- apps/api/src/middleware/zodValidate.ts | 14 +-- apps/api/src/orders/router.ts | 30 +++-- packages/lib/graphql/__generated__/gql.ts | 26 ++--- packages/lib/graphql/__generated__/graphql.ts | 104 ++++++++++++++++-- 13 files changed, 235 insertions(+), 64 deletions(-) create mode 100644 apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx create mode 100644 apps/api/src/businesses/operations/verifyBusiness.ts diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx index 367573a2..14efb6ff 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx @@ -1,9 +1,39 @@ -import { Business } from "@sahil/lib/graphql/__generated__/graphql"; +import { useForm, SubmitHandler } from "react-hook-form"; +import { useRouter } from "next/router"; +import { z } from "zod"; +import { Card, FormControl } from "ui"; +import { HiArrowSmallLeft, HiArrowSmallRight } from "react-icons/hi2"; + +const businessAddressSchema = z.object({ + streetName: z.string().min(2, { message: "Must be more than 2 characters" }), +}); + +type FormData = z.infer; export const AddressInfo = () => { + const onSubmit: SubmitHandler = async (data) => { + const validatedInput = businessAddressSchema.parse(data); + }; return ( -
-

Address Info

-
+ + + + + + + +
+ + +
+
); }; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx index f2c4c970..8cf16310 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx @@ -37,6 +37,15 @@ export const BusinessInfo = () => { type="text" className="input input-sm input-bordered w-full bg-gray-100" placeholder="Keji's Foods" + {...register("name")} + /> + + +
diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx new file mode 100644 index 00000000..501515a0 --- /dev/null +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx @@ -0,0 +1,22 @@ +import { Business } from "@sahil/lib/graphql/__generated__/graphql"; +import { Card, FormControl } from "ui"; +import { HiArrowSmallLeft, HiArrowSmallRight } from "react-icons/hi2"; + +export const BusinessPreferencesInfo = () => { + return ( + +

Business Preferences

+ + + +
+ + +
+
+ ); +}; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx index 4d232227..8411d5ac 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx @@ -3,3 +3,4 @@ export * from "./BusinessInfo"; export * from "./BusinessInfoSummary"; export * from "./BusinessFormSteps"; export * from "./BusinessStepsPaginator"; +export * from "./BusinessPreferencesInfo"; diff --git a/apps/agent/src/pages/businesses/register/[...step].tsx b/apps/agent/src/pages/businesses/register/[...step].tsx index e2c6ea40..15fdc6df 100644 --- a/apps/agent/src/pages/businesses/register/[...step].tsx +++ b/apps/agent/src/pages/businesses/register/[...step].tsx @@ -8,6 +8,7 @@ import { BusinessInfoSummary, BusinessFormSteps, BusinessStepsPaginator, + BusinessPreferencesInfo, } from "@/Businesses/BusinessRegistrationForm"; import { HiOutlineCheckCircle, @@ -92,6 +93,7 @@ export default function BusinessRegistrationPage() { /> {currentStep === "business_info" && } {currentStep === "address_info" && } + {currentStep === "preferences" && } {currentStep === "summary" && }
diff --git a/apps/agent/tailwind.config.ts b/apps/agent/tailwind.config.ts index fed7bffa..146a7270 100644 --- a/apps/agent/tailwind.config.ts +++ b/apps/agent/tailwind.config.ts @@ -28,7 +28,7 @@ const extendedConfig: Config = { ...require("daisyui/src/theming/themes")["[data-theme=lemonade]"], primary: "#067a46", secondary: "#07ba3d", - accent: "#40efcf", + accent: "#FFDB58", neutral: "#2d2f39", "base-100": "#ffffff", info: "#76d1e5", diff --git a/apps/api/src/businesses/operations/registerBusiness.ts b/apps/api/src/businesses/operations/registerBusiness.ts index 2bb791af..0f6a2523 100644 --- a/apps/api/src/businesses/operations/registerBusiness.ts +++ b/apps/api/src/businesses/operations/registerBusiness.ts @@ -1,28 +1,30 @@ import { z } from "zod"; -import { gql } from "graphql-request"; +import { INSERT_NEW_BUSINESS } from "@sahil/lib/graphql/mutations/businesses"; import { client } from "../../lib/graphql-request"; -const query = gql` - query getBusinesses { - business { - created_at - id - updated_at - name - } - } -`; +type ContactMethod = "email" | "call" | "sms" | "whatsapp"; + +type DeliveryMethod = "pick-up-location" | "direct-delivery"; export const businessSchema = z.object({ name: z.string(), + // type: z.string(), + // description: z.string(), + // contactEmail: z.string(), + // contactName: z.string(), + // preferredContactMethod: z.string(), + // preferredDeliveryMethod: z.string() }); export type BusinessAttributes = z.infer; -export const registerBusiness = async (business: BusinessAttributes) => { - const data = await client.request(query); - console.log(business); - console.log(data); - return business; +export const registerBusiness = async ( + business: BusinessAttributes +): Promise => { + const data = await client.request(INSERT_NEW_BUSINESS, { + object: business, + }); + // @ts-ignore + return data?.insert_business_one; }; diff --git a/apps/api/src/businesses/operations/verifyBusiness.ts b/apps/api/src/businesses/operations/verifyBusiness.ts new file mode 100644 index 00000000..3250e16e --- /dev/null +++ b/apps/api/src/businesses/operations/verifyBusiness.ts @@ -0,0 +1 @@ +export const verifyBusinessLink = () => {}; diff --git a/apps/api/src/businesses/router.ts b/apps/api/src/businesses/router.ts index b6027f35..60fa9066 100644 --- a/apps/api/src/businesses/router.ts +++ b/apps/api/src/businesses/router.ts @@ -5,22 +5,26 @@ import { validate } from "../middleware/zodValidate"; import { registerBusiness, businessSchema, + BusinessAttributes, } from "./operations/registerBusiness"; const businessRouter = Router(); businessRouter.use(logRequest); -// register a business businessRouter.post( "/", - validate(businessSchema), - async (req: Request, res: Response, next: NextFunction) => { + validate(businessSchema), + async ( + req: Request, + res: Response, + next: NextFunction + ) => { try { - // @ts-ignore const business = await registerBusiness(req.body); - res.send({ - business, + // console.log("business", business); + res.status(201).json({ + ...business, }); } catch (error) { next(error); diff --git a/apps/api/src/middleware/zodValidate.ts b/apps/api/src/middleware/zodValidate.ts index bd8d0569..5ab91a91 100644 --- a/apps/api/src/middleware/zodValidate.ts +++ b/apps/api/src/middleware/zodValidate.ts @@ -1,5 +1,5 @@ import { NextFunction, Response, Router, Request } from "express"; -import { logger } from "../lib/winston"; +import { z, ZodError } from "zod"; const extractInputFromHasuraAction = (body: any): any | null => { if ("action" in body && "input" in body) { @@ -13,18 +13,14 @@ const extractInputFromHasuraAction = (body: any): any | null => { return null; }; -export const validate = - (schema: any) => (req: Request, res: Response, next: NextFunction) => { +export function validate(schema: z.ZodType) { + return (req: Request, res: Response, next: NextFunction) => { try { const input = extractInputFromHasuraAction(req.body); - const validatedInput = schema.parse(input); - // @ts-ignore - req.locals = { - hello: "world", - }; - + req.body = schema.parse(input); next(); } catch (error: any) { return res.status(400).json(error.errors); } }; +} diff --git a/apps/api/src/orders/router.ts b/apps/api/src/orders/router.ts index 84a11ed0..1a9b4b68 100644 --- a/apps/api/src/orders/router.ts +++ b/apps/api/src/orders/router.ts @@ -4,23 +4,37 @@ import { z } from "zod"; import { logger } from "../lib/winston"; import { logRequest } from "../middleware/requestLogger"; import { validate } from "../middleware/zodValidate"; -import { initOrder, orderSchema } from "./operations/initOrder"; +import { + initOrder, + orderSchema, + OrderAttributes, +} from "./operations/initOrder"; import { processOrder } from "./operations/processOrder"; const ordersRouter = Router(); ordersRouter.use(logRequest); +type OrdersActionType = { + created_at: Date; + customerId: string; + destination: string; + id: string; + orderId: string; + origin: string; + processedBy: string; +}; + ordersRouter.post( "/", - validate(orderSchema), - async (req: Request, res: Response, next: NextFunction) => { + validate(orderSchema), + async (req: Request, res: Response, next: NextFunction) => { try { - const { object } = req.body.input; - const validatedInput = validate(object); - await pushIntoOrders(validatedInput); - return res.status(200).json({ - order: object, + const order = await initOrder(req.body); + // push into Queue + await pushIntoOrders(req.body); + res.status(201).send({ + ...order, }); } catch (error) { next(error); diff --git a/packages/lib/graphql/__generated__/gql.ts b/packages/lib/graphql/__generated__/gql.ts index f1257fd9..ae0a570b 100644 --- a/packages/lib/graphql/__generated__/gql.ts +++ b/packages/lib/graphql/__generated__/gql.ts @@ -13,7 +13,7 @@ import { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n mutation registerClient($object: business_insert_input!) {\n insert_business_one(object: $object) {\n id\n name\n }\n }\n": + "\n mutation registerClient($object: business_insert_input!) {\n insert_business_one(object: $object) {\n id\n name\n description\n type\n }\n }\n": types.RegisterClientDocument, "\n mutation insertBusinessAddress($object: addresses_insert_input!) {\n insert_addresses_one(object: $object) {\n business_id\n city\n }\n }\n": types.InsertBusinessAddressDocument, @@ -33,8 +33,8 @@ const documents = { types.AddNewProductDocument, "\n mutation registerUser($object: users_insert_input!) {\n insert_users_one(object: $object) {\n id\n name\n }\n }\n": types.RegisterUserDocument, - "\n query getClients {\n business {\n created_at\n id\n updated_at\n name\n contactName\n type\n phoneNumber\n description\n contactEmail\n addresses {\n city\n created_at\n id\n latitude\n longitude\n updated_at\n street_address\n }\n }\n business_aggregate {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n": - types.GetClientsDocument, + "\n query getBusinesses {\n business {\n created_at\n id\n updated_at\n name\n contactName\n type\n phoneNumber\n description\n contactEmail\n addresses {\n city\n created_at\n id\n latitude\n longitude\n updated_at\n street_address\n }\n }\n business_aggregate {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n": + types.GetBusinessesDocument, "\n query getBusinessOrders(\n $customerId: uuid\n $limit: Int = 4\n $offset: Int = 0\n ) {\n orders(\n where: {\n _or: [\n { customerId: { _eq: $customerId } }\n { customerId: { _is_null: true } }\n ]\n customerId: { _eq: $customerId }\n }\n limit: $limit\n offset: $offset\n ) {\n id\n created_at\n destination\n id\n orderId\n customerId\n origin\n status\n business {\n contactName\n phoneNumber\n name\n }\n }\n orders_aggregate(where: { customerId: { _eq: $customerId } }) {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n": types.GetBusinessOrdersDocument, "\n query getBusinessByPK($id: uuid!) {\n business_by_pk(id: $id) {\n id\n name\n contactName\n phoneNumber\n description\n contactEmail\n type\n agent {\n name\n id\n }\n addresses {\n city\n street_address\n }\n }\n }\n": @@ -65,9 +65,9 @@ const documents = { types.GetFilteredSuppliersDocument, "\n query getSupplierByPK($id: uuid!) {\n suppliers_by_pk(id: $id) {\n created_at\n id\n name\n description\n phoneNumber\n contactName\n contactEmail\n streetAddress\n zone\n categories {\n category_name\n }\n products_aggregate {\n aggregate {\n count\n }\n }\n }\n }\n": types.GetSupplierByPkDocument, - "\n query getSupplierProducts(\n $id: uuid!\n $offset: Int = 0\n $order_by: [products_order_by!] = {}\n ) {\n products(\n where: { supplier_id: { _eq: $id } }\n limit: 4\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n": + "\n query getSupplierProducts(\n $id: uuid!\n $offset: Int = 0\n $limit: Int = 4\n $order_by: [products_order_by!] = { name: asc }\n ) {\n products(\n where: { supplier_id: { _eq: $id } }\n limit: $limit\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n": types.GetSupplierProductsDocument, - '\n query getSupplierProductByName(\n $id: uuid!\n $offset: Int = 0\n $name: String = ""\n $limit: Int = 4\n ) {\n products(\n where: { supplier_id: { _eq: $id }, name: { _ilike: $name } }\n limit: $limit\n offset: $offset\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n': + '\n query getSupplierProductByName(\n $id: uuid!\n $offset: Int = 0\n $name: String = ""\n $limit: Int = 4\n $order_by: [products_order_by!] = { name: asc }\n ) {\n products(\n where: { supplier_id: { _eq: $id }, name: { _ilike: $name } }\n limit: $limit\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n': types.GetSupplierProductByNameDocument, "\n query getUsers {\n users {\n id\n created_at\n role\n name\n }\n }\n": types.GetUsersDocument, @@ -93,8 +93,8 @@ export function gql(source: string): unknown; * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( - source: "\n mutation registerClient($object: business_insert_input!) {\n insert_business_one(object: $object) {\n id\n name\n }\n }\n" -): (typeof documents)["\n mutation registerClient($object: business_insert_input!) {\n insert_business_one(object: $object) {\n id\n name\n }\n }\n"]; + source: "\n mutation registerClient($object: business_insert_input!) {\n insert_business_one(object: $object) {\n id\n name\n description\n type\n }\n }\n" +): (typeof documents)["\n mutation registerClient($object: business_insert_input!) {\n insert_business_one(object: $object) {\n id\n name\n description\n type\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -153,8 +153,8 @@ export function gql( * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( - source: "\n query getClients {\n business {\n created_at\n id\n updated_at\n name\n contactName\n type\n phoneNumber\n description\n contactEmail\n addresses {\n city\n created_at\n id\n latitude\n longitude\n updated_at\n street_address\n }\n }\n business_aggregate {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n" -): (typeof documents)["\n query getClients {\n business {\n created_at\n id\n updated_at\n name\n contactName\n type\n phoneNumber\n description\n contactEmail\n addresses {\n city\n created_at\n id\n latitude\n longitude\n updated_at\n street_address\n }\n }\n business_aggregate {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n"]; + source: "\n query getBusinesses {\n business {\n created_at\n id\n updated_at\n name\n contactName\n type\n phoneNumber\n description\n contactEmail\n addresses {\n city\n created_at\n id\n latitude\n longitude\n updated_at\n street_address\n }\n }\n business_aggregate {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n" +): (typeof documents)["\n query getBusinesses {\n business {\n created_at\n id\n updated_at\n name\n contactName\n type\n phoneNumber\n description\n contactEmail\n addresses {\n city\n created_at\n id\n latitude\n longitude\n updated_at\n street_address\n }\n }\n business_aggregate {\n aggregate {\n count(columns: id, distinct: true)\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -249,14 +249,14 @@ export function gql( * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( - source: "\n query getSupplierProducts(\n $id: uuid!\n $offset: Int = 0\n $order_by: [products_order_by!] = {}\n ) {\n products(\n where: { supplier_id: { _eq: $id } }\n limit: 4\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n" -): (typeof documents)["\n query getSupplierProducts(\n $id: uuid!\n $offset: Int = 0\n $order_by: [products_order_by!] = {}\n ) {\n products(\n where: { supplier_id: { _eq: $id } }\n limit: 4\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n"]; + source: "\n query getSupplierProducts(\n $id: uuid!\n $offset: Int = 0\n $limit: Int = 4\n $order_by: [products_order_by!] = { name: asc }\n ) {\n products(\n where: { supplier_id: { _eq: $id } }\n limit: $limit\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n" +): (typeof documents)["\n query getSupplierProducts(\n $id: uuid!\n $offset: Int = 0\n $limit: Int = 4\n $order_by: [products_order_by!] = { name: asc }\n ) {\n products(\n where: { supplier_id: { _eq: $id } }\n limit: $limit\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( - source: '\n query getSupplierProductByName(\n $id: uuid!\n $offset: Int = 0\n $name: String = ""\n $limit: Int = 4\n ) {\n products(\n where: { supplier_id: { _eq: $id }, name: { _ilike: $name } }\n limit: $limit\n offset: $offset\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n' -): (typeof documents)['\n query getSupplierProductByName(\n $id: uuid!\n $offset: Int = 0\n $name: String = ""\n $limit: Int = 4\n ) {\n products(\n where: { supplier_id: { _eq: $id }, name: { _ilike: $name } }\n limit: $limit\n offset: $offset\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n']; + source: '\n query getSupplierProductByName(\n $id: uuid!\n $offset: Int = 0\n $name: String = ""\n $limit: Int = 4\n $order_by: [products_order_by!] = { name: asc }\n ) {\n products(\n where: { supplier_id: { _eq: $id }, name: { _ilike: $name } }\n limit: $limit\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n' +): (typeof documents)['\n query getSupplierProductByName(\n $id: uuid!\n $offset: Int = 0\n $name: String = ""\n $limit: Int = 4\n $order_by: [products_order_by!] = { name: asc }\n ) {\n products(\n where: { supplier_id: { _eq: $id }, name: { _ilike: $name } }\n limit: $limit\n offset: $offset\n order_by: $order_by\n ) {\n id\n name\n description\n inStock\n quantity\n price\n }\n }\n']; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/lib/graphql/__generated__/graphql.ts b/packages/lib/graphql/__generated__/graphql.ts index 8b3ee2e1..ef418e39 100644 --- a/packages/lib/graphql/__generated__/graphql.ts +++ b/packages/lib/graphql/__generated__/graphql.ts @@ -2976,6 +2976,8 @@ export type Business = { owner?: Maybe; owner_id?: Maybe; phoneNumber?: Maybe; + preferredContactMethod?: Maybe; + preferredDeliveryMethod?: Maybe; /** An object relationship */ registeration_channel_type?: Maybe; registered_by?: Maybe; @@ -3086,6 +3088,8 @@ export type Business_Bool_Exp = { owner?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registeration_channel_type?: InputMaybe; registered_by?: InputMaybe; registration_channel?: InputMaybe; @@ -3114,6 +3118,8 @@ export type Business_Insert_Input = { owner?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registeration_channel_type?: InputMaybe; registered_by?: InputMaybe; registration_channel?: InputMaybe; @@ -3132,6 +3138,8 @@ export type Business_Max_Fields = { name?: Maybe; owner_id?: Maybe; phoneNumber?: Maybe; + preferredContactMethod?: Maybe; + preferredDeliveryMethod?: Maybe; registered_by?: Maybe; updated_at?: Maybe; }; @@ -3146,6 +3154,8 @@ export type Business_Max_Order_By = { name?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registered_by?: InputMaybe; updated_at?: InputMaybe; }; @@ -3161,6 +3171,8 @@ export type Business_Min_Fields = { name?: Maybe; owner_id?: Maybe; phoneNumber?: Maybe; + preferredContactMethod?: Maybe; + preferredDeliveryMethod?: Maybe; registered_by?: Maybe; updated_at?: Maybe; }; @@ -3175,6 +3187,8 @@ export type Business_Min_Order_By = { name?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registered_by?: InputMaybe; updated_at?: InputMaybe; }; @@ -3217,6 +3231,8 @@ export type Business_Order_By = { owner?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registeration_channel_type?: InputMaybe; registered_by?: InputMaybe; registration_channel?: InputMaybe; @@ -3369,6 +3385,10 @@ export enum Business_Select_Column { /** column name */ PhoneNumber = "phoneNumber", /** column name */ + PreferredContactMethod = "preferredContactMethod", + /** column name */ + PreferredDeliveryMethod = "preferredDeliveryMethod", + /** column name */ RegisteredBy = "registered_by", /** column name */ RegistrationChannel = "registration_channel", @@ -3388,6 +3408,8 @@ export type Business_Set_Input = { name?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registered_by?: InputMaybe; registration_channel?: InputMaybe; type?: InputMaybe; @@ -3412,6 +3434,8 @@ export type Business_Stream_Cursor_Value_Input = { name?: InputMaybe; owner_id?: InputMaybe; phoneNumber?: InputMaybe; + preferredContactMethod?: InputMaybe; + preferredDeliveryMethod?: InputMaybe; registered_by?: InputMaybe; registration_channel?: InputMaybe; type?: InputMaybe; @@ -3606,6 +3630,10 @@ export enum Business_Update_Column { /** column name */ PhoneNumber = "phoneNumber", /** column name */ + PreferredContactMethod = "preferredContactMethod", + /** column name */ + PreferredDeliveryMethod = "preferredDeliveryMethod", + /** column name */ RegisteredBy = "registered_by", /** column name */ RegistrationChannel = "registration_channel", @@ -13689,6 +13717,8 @@ export type RegisterClientMutation = { __typename?: "business"; id: any; name?: string | null; + description?: string | null; + type?: Business_Type_Enum | null; } | null; }; @@ -13813,9 +13843,9 @@ export type RegisterUserMutation = { } | null; }; -export type GetClientsQueryVariables = Exact<{ [key: string]: never }>; +export type GetBusinessesQueryVariables = Exact<{ [key: string]: never }>; -export type GetClientsQuery = { +export type GetBusinessesQuery = { __typename?: "query_root"; business: Array<{ __typename?: "business"; @@ -14209,6 +14239,7 @@ export type GetSupplierByPkQuery = { export type GetSupplierProductsQueryVariables = Exact<{ id: Scalars["uuid"]["input"]; offset?: InputMaybe; + limit?: InputMaybe; order_by?: InputMaybe | Products_Order_By>; }>; @@ -14230,6 +14261,7 @@ export type GetSupplierProductByNameQueryVariables = Exact<{ offset?: InputMaybe; name?: InputMaybe; limit?: InputMaybe; + order_by?: InputMaybe | Products_Order_By>; }>; export type GetSupplierProductByNameQuery = { @@ -14329,6 +14361,8 @@ export const RegisterClientDocument = { selections: [ { kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, + { kind: "Field", name: { kind: "Name", value: "description" } }, + { kind: "Field", name: { kind: "Name", value: "type" } }, ], }, }, @@ -14913,13 +14947,13 @@ export const RegisterUserDocument = { RegisterUserMutation, RegisterUserMutationVariables >; -export const GetClientsDocument = { +export const GetBusinessesDocument = { kind: "Document", definitions: [ { kind: "OperationDefinition", operation: "query", - name: { kind: "Name", value: "getClients" }, + name: { kind: "Name", value: "getBusinesses" }, selectionSet: { kind: "SelectionSet", selections: [ @@ -15013,7 +15047,7 @@ export const GetClientsDocument = { }, }, ], -} as unknown as DocumentNode; +} as unknown as DocumentNode; export const GetBusinessOrdersDocument = { kind: "Document", definitions: [ @@ -16672,6 +16706,15 @@ export const GetSupplierProductsDocument = { type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, defaultValue: { kind: "IntValue", value: "0" }, }, + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "limit" }, + }, + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + defaultValue: { kind: "IntValue", value: "4" }, + }, { kind: "VariableDefinition", variable: { @@ -16688,7 +16731,16 @@ export const GetSupplierProductsDocument = { }, }, }, - defaultValue: { kind: "ObjectValue", fields: [] }, + defaultValue: { + kind: "ObjectValue", + fields: [ + { + kind: "ObjectField", + name: { kind: "Name", value: "name" }, + value: { kind: "EnumValue", value: "asc" }, + }, + ], + }, }, ], selectionSet: { @@ -16727,7 +16779,10 @@ export const GetSupplierProductsDocument = { { kind: "Argument", name: { kind: "Name", value: "limit" }, - value: { kind: "IntValue", value: "4" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "limit" }, + }, }, { kind: "Argument", @@ -16806,6 +16861,33 @@ export const GetSupplierProductByNameDocument = { type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, defaultValue: { kind: "IntValue", value: "4" }, }, + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "order_by" }, + }, + type: { + kind: "ListType", + type: { + kind: "NonNullType", + type: { + kind: "NamedType", + name: { kind: "Name", value: "products_order_by" }, + }, + }, + }, + defaultValue: { + kind: "ObjectValue", + fields: [ + { + kind: "ObjectField", + name: { kind: "Name", value: "name" }, + value: { kind: "EnumValue", value: "asc" }, + }, + ], + }, + }, ], selectionSet: { kind: "SelectionSet", @@ -16873,6 +16955,14 @@ export const GetSupplierProductByNameDocument = { name: { kind: "Name", value: "offset" }, }, }, + { + kind: "Argument", + name: { kind: "Name", value: "order_by" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "order_by" }, + }, + }, ], selectionSet: { kind: "SelectionSet", From 24568483280f5556a2285340814d9e7ceba3d621 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 20:12:59 +0300 Subject: [PATCH 05/11] feat: add client queues --- apps/api/src/businesses/router.ts | 4 ++-- apps/api/src/businesses/worker.ts | 30 ++++++++++++++++++++++++++ apps/api/src/enqueue.ts | 4 ++++ apps/api/src/lib/graphql-request.ts | 3 ++- apps/api/src/middleware/zodValidate.ts | 4 ++-- apps/api/src/orders/router.ts | 2 -- apps/api/src/orders/worker.ts | 3 ++- apps/api/src/queue.ts | 2 +- 8 files changed, 43 insertions(+), 9 deletions(-) diff --git a/apps/api/src/businesses/router.ts b/apps/api/src/businesses/router.ts index 60fa9066..a4305930 100644 --- a/apps/api/src/businesses/router.ts +++ b/apps/api/src/businesses/router.ts @@ -1,5 +1,4 @@ import { NextFunction, Response, Router, Request } from "express"; -import { logger } from "../lib/winston"; import { logRequest } from "../middleware/requestLogger"; import { validate } from "../middleware/zodValidate"; import { @@ -7,6 +6,7 @@ import { businessSchema, BusinessAttributes, } from "./operations/registerBusiness"; +import { pushIntoClient } from "../enqueue"; const businessRouter = Router(); @@ -22,7 +22,7 @@ businessRouter.post( ) => { try { const business = await registerBusiness(req.body); - // console.log("business", business); + pushIntoClient(business); res.status(201).json({ ...business, }); diff --git a/apps/api/src/businesses/worker.ts b/apps/api/src/businesses/worker.ts index e69de29b..b382644f 100644 --- a/apps/api/src/businesses/worker.ts +++ b/apps/api/src/businesses/worker.ts @@ -0,0 +1,30 @@ +import { Worker } from "bullmq"; +import { logger } from "../lib/winston"; +import { connection } from "../lib/ioredis"; +import { Queues } from "../queue"; + +const worker = new Worker( + Queues.Business, + async (job) => { + console.log("job", job); + logger.info("Processing Job", { + world: "hello 0", + }); + }, + { + connection, + } +); + +worker.on("completed", (job) => { + logger.info(`${job.id} has completed!`, { + world: "hello 1", + }); +}); + +worker.on("failed", (job, err) => { + // @ts-ignore + logger.info(`${job.id} has failed with ${err.message}`, { + world: "hello 2", + }); +}); diff --git a/apps/api/src/enqueue.ts b/apps/api/src/enqueue.ts index d63da3a4..1c81d863 100644 --- a/apps/api/src/enqueue.ts +++ b/apps/api/src/enqueue.ts @@ -3,7 +3,11 @@ import { create, Queues } from "./queue"; export type Enqueue = (data: T) => Promise; +export const clientQueue = create(Queues.Client); export const ordersQueue = create(Queues.Order); +export const pushIntoClient: Enqueue = (message) => + ordersQueue.add("new-client", message); + export const pushIntoOrders: Enqueue = (message) => ordersQueue.add("new-order", message); diff --git a/apps/api/src/lib/graphql-request.ts b/apps/api/src/lib/graphql-request.ts index 635447ca..24a00758 100644 --- a/apps/api/src/lib/graphql-request.ts +++ b/apps/api/src/lib/graphql-request.ts @@ -2,10 +2,11 @@ import { graphQLClient } from "@sahil/lib/graphql/graphql-request"; import { hasuraAdminSecret, hasuraEndpoint } from "../config"; const endpoint = hasuraEndpoint; +const token = ""; export const client = graphQLClient(endpoint, { headers: { - authorization: `Bearer MY_TOKEN`, + authorization: token, "x-hasura-admin-secret": hasuraAdminSecret, "x-hasura-role": "user", }, diff --git a/apps/api/src/middleware/zodValidate.ts b/apps/api/src/middleware/zodValidate.ts index 5ab91a91..ad23881f 100644 --- a/apps/api/src/middleware/zodValidate.ts +++ b/apps/api/src/middleware/zodValidate.ts @@ -1,5 +1,5 @@ -import { NextFunction, Response, Router, Request } from "express"; -import { z, ZodError } from "zod"; +import { NextFunction, Response, Request } from "express"; +import { z } from "zod"; const extractInputFromHasuraAction = (body: any): any | null => { if ("action" in body && "input" in body) { diff --git a/apps/api/src/orders/router.ts b/apps/api/src/orders/router.ts index 1a9b4b68..f0288163 100644 --- a/apps/api/src/orders/router.ts +++ b/apps/api/src/orders/router.ts @@ -1,7 +1,5 @@ import { NextFunction, Response, Router, Request } from "express"; import { pushIntoOrders } from "../enqueue"; -import { z } from "zod"; -import { logger } from "../lib/winston"; import { logRequest } from "../middleware/requestLogger"; import { validate } from "../middleware/zodValidate"; import { diff --git a/apps/api/src/orders/worker.ts b/apps/api/src/orders/worker.ts index 5101cd5c..5cbf1148 100644 --- a/apps/api/src/orders/worker.ts +++ b/apps/api/src/orders/worker.ts @@ -1,9 +1,10 @@ import { Worker } from "bullmq"; import { logger } from "../lib/winston"; import { connection } from "../lib/ioredis"; +import { Queues } from "../queue"; const worker = new Worker( - "Order", + Queues.Order, async (job) => { logger.info("Processing Job", { world: "hello 0", diff --git a/apps/api/src/queue.ts b/apps/api/src/queue.ts index 762cd7b1..818094a1 100644 --- a/apps/api/src/queue.ts +++ b/apps/api/src/queue.ts @@ -2,7 +2,7 @@ import { Queue } from "bullmq"; import { connection } from "./lib/ioredis"; export enum Queues { - Business = "Business", + Client = "Client", Event = "Event", Mail = "Mail", Notification = "Notification", From e2068a6a7f84ab6f149201b2f9529d437de9674d Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 20:53:02 +0300 Subject: [PATCH 06/11] feat: add register business action subscription --- .../BusinessInfoSummary.tsx | 2 ++ .../src/businesses/operations/registerBusiness.ts | 2 +- apps/api/src/businesses/router.ts | 2 +- apps/api/src/businesses/worker.ts | 2 +- apps/api/src/middleware/zodValidate.ts | 2 +- apps/api/src/orders/router.ts | 2 +- apps/client/src/hooks/businesses.ts | 14 +++++++++++++- packages/lib/graphql/subscriptions/businesses.ts | 15 +++++++++++++++ 8 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 packages/lib/graphql/subscriptions/businesses.ts diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx index 25282c7d..b78c6005 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx @@ -1,3 +1,5 @@ +// import { useRegisterBusiness, useBusinessValidated } from "@/hooks/businesses"; + export const BusinessInfoSummary = () => { return (
diff --git a/apps/api/src/businesses/operations/registerBusiness.ts b/apps/api/src/businesses/operations/registerBusiness.ts index 0f6a2523..aa99d573 100644 --- a/apps/api/src/businesses/operations/registerBusiness.ts +++ b/apps/api/src/businesses/operations/registerBusiness.ts @@ -8,7 +8,7 @@ type ContactMethod = "email" | "call" | "sms" | "whatsapp"; type DeliveryMethod = "pick-up-location" | "direct-delivery"; export const businessSchema = z.object({ - name: z.string(), + name: z.string().trim(), // type: z.string(), // description: z.string(), // contactEmail: z.string(), diff --git a/apps/api/src/businesses/router.ts b/apps/api/src/businesses/router.ts index a4305930..1dd647fd 100644 --- a/apps/api/src/businesses/router.ts +++ b/apps/api/src/businesses/router.ts @@ -14,7 +14,7 @@ businessRouter.use(logRequest); businessRouter.post( "/", - validate(businessSchema), + validate(businessSchema), async ( req: Request, res: Response, diff --git a/apps/api/src/businesses/worker.ts b/apps/api/src/businesses/worker.ts index b382644f..8ae41901 100644 --- a/apps/api/src/businesses/worker.ts +++ b/apps/api/src/businesses/worker.ts @@ -4,7 +4,7 @@ import { connection } from "../lib/ioredis"; import { Queues } from "../queue"; const worker = new Worker( - Queues.Business, + Queues.Client, async (job) => { console.log("job", job); logger.info("Processing Job", { diff --git a/apps/api/src/middleware/zodValidate.ts b/apps/api/src/middleware/zodValidate.ts index ad23881f..b346847c 100644 --- a/apps/api/src/middleware/zodValidate.ts +++ b/apps/api/src/middleware/zodValidate.ts @@ -13,7 +13,7 @@ const extractInputFromHasuraAction = (body: any): any | null => { return null; }; -export function validate(schema: z.ZodType) { +export function validate(schema: T) { return (req: Request, res: Response, next: NextFunction) => { try { const input = extractInputFromHasuraAction(req.body); diff --git a/apps/api/src/orders/router.ts b/apps/api/src/orders/router.ts index f0288163..5d607358 100644 --- a/apps/api/src/orders/router.ts +++ b/apps/api/src/orders/router.ts @@ -25,7 +25,7 @@ type OrdersActionType = { ordersRouter.post( "/", - validate(orderSchema), + validate(orderSchema), async (req: Request, res: Response, next: NextFunction) => { try { const order = await initOrder(req.body); diff --git a/apps/client/src/hooks/businesses.ts b/apps/client/src/hooks/businesses.ts index dc14d25d..5bfc8224 100644 --- a/apps/client/src/hooks/businesses.ts +++ b/apps/client/src/hooks/businesses.ts @@ -1,4 +1,4 @@ -import { useMutation, useQuery } from "@apollo/client"; +import { useMutation, useQuery, useSubscription } from "@apollo/client"; import { FETCH_BUSINESSES, FETCH_BUSINESS_BY_PK, @@ -6,6 +6,8 @@ import { FETCH_BUSINESS_ORDERS, } from "@sahil/lib/graphql"; +import { BUSINESS_VALIDATED } from "@sahil/lib/graphql/subscriptions/businesses"; + // graphql types import { GetBusinessByPkQuery, @@ -69,3 +71,13 @@ export const useFetchBusinessOrders = ({ ordersCount: data?.orders_aggregate?.aggregate, }; }; + +export const useBusinessValidated = (actionId: string) => { + const { data, loading, error } = useSubscription(BUSINESS_VALIDATED, { + variables: { + id: actionId, + }, + skip: !actionId, + }); + return { data, error, loading }; +}; diff --git a/packages/lib/graphql/subscriptions/businesses.ts b/packages/lib/graphql/subscriptions/businesses.ts new file mode 100644 index 00000000..478cda81 --- /dev/null +++ b/packages/lib/graphql/subscriptions/businesses.ts @@ -0,0 +1,15 @@ +import { gql } from "@apollo/client"; + +export const BUSINESS_VALIDATED = gql` + subscription MySubscription { + registerBusinessAction(id: "a9872403-36db-4423-ab05-b8d1d4dec326") { + created_at + errors + id + output { + id + name + } + } + } +`; From ca50c151f71a4a06fd58fc351c0a0a6be10d7897 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 21 Jan 2024 22:59:06 +0300 Subject: [PATCH 07/11] feat: enhance validation schema --- .../BusinessInfoSummary.tsx | 1 + .../businesses/operations/registerBusiness.ts | 5 ++++ apps/api/src/orders/operations/initOrder.ts | 27 ++++++++++++------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx index b78c6005..b7ef9829 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx @@ -1,5 +1,6 @@ // import { useRegisterBusiness, useBusinessValidated } from "@/hooks/businesses"; +// async refine to check whether entry exists or not export const BusinessInfoSummary = () => { return (
diff --git a/apps/api/src/businesses/operations/registerBusiness.ts b/apps/api/src/businesses/operations/registerBusiness.ts index aa99d573..a3dad9c1 100644 --- a/apps/api/src/businesses/operations/registerBusiness.ts +++ b/apps/api/src/businesses/operations/registerBusiness.ts @@ -15,6 +15,11 @@ export const businessSchema = z.object({ // contactName: z.string(), // preferredContactMethod: z.string(), // preferredDeliveryMethod: z.string() + // price: z + // .string() + // .min(1, { message: "required" }) + // .transform((value) => +value) + // .refine((value) => !isNaN(value), { message: "Must be a number"}) }); export type BusinessAttributes = z.infer; diff --git a/apps/api/src/orders/operations/initOrder.ts b/apps/api/src/orders/operations/initOrder.ts index f10cb9d2..f228435e 100644 --- a/apps/api/src/orders/operations/initOrder.ts +++ b/apps/api/src/orders/operations/initOrder.ts @@ -1,14 +1,22 @@ import { z } from "zod"; +import { client } from "../../lib/graphql-request"; -export const orderSchema = z.object({ - orderId: z.string(), - created_at: z.date(), - customerId: z.string(), - destination: z.string(), - id: z.string(), - origin: z.string(), - processedBy: z.string(), -}); +export const orderSchema = z + .object({ + orderId: z.string(), + created_at: z.date().refine((value) => value > new Date()), + customerId: z.string(), + destination: z.string(), + id: z.string(), + origin: z.string(), + processedBy: z.string(), + }) + .refine( + ({ destination, origin }) => { + return origin !== destination; + }, + { message: "Destination is the same as origin" } + ); export type OrderAttributes = z.infer; @@ -16,6 +24,7 @@ export const initOrder = ( attributes: OrderAttributes ): Promise => { return new Promise((resolve) => { + // check if client is registered // check for clients that can process this order // update order status based on this information // alert the notifications service From c4ff7ee3d2f0e09243b200d95020bb4bf6c8915c Mon Sep 17 00:00:00 2001 From: Eman Date: Mon, 22 Jan 2024 14:56:27 +0300 Subject: [PATCH 08/11] feat: add business registration form components --- apps/agent/next.config.js | 2 +- apps/agent/package.json | 1 + apps/agent/src/Businesses/AddNewBusiness.tsx | 56 ------------ ...ddressInfo.tsx => BusinessAddressInfo.tsx} | 11 ++- .../BusinessRegistrationForm/BusinessInfo.tsx | 8 +- .../BusinessInfoSummary.tsx | 7 +- .../BusinessPreferencesInfo.tsx | 88 +++++++++++++++---- .../BusinessRegistrationForm/index.tsx | 2 +- .../OrderProcessingForm/PaymentDetails.tsx | 2 +- .../pages/businesses/register/[...step].tsx | 4 +- apps/client/next.config.js | 2 +- apps/client/package.json | 3 +- .../BusinessRegistrationForm/AddressInfo.tsx | 2 +- .../BusinessRegistrationForm/index.tsx | 2 +- packages/eslint-config-custom/index.js | 2 +- .../businesses/BusinessOrderHistory.tsx | 5 ++ packages/features/businesses/zod-schema.ts | 18 ++++ packages/features/package.json | 10 +++ packages/ui/components/AsyncInput.tsx | 38 ++++++++ packages/ui/components/Radio.tsx | 21 +++++ packages/ui/index.tsx | 1 + 21 files changed, 194 insertions(+), 91 deletions(-) delete mode 100644 apps/agent/src/Businesses/AddNewBusiness.tsx rename apps/agent/src/Businesses/BusinessRegistrationForm/{AddressInfo.tsx => BusinessAddressInfo.tsx} (79%) create mode 100644 packages/features/businesses/BusinessOrderHistory.tsx create mode 100644 packages/features/businesses/zod-schema.ts create mode 100644 packages/features/package.json create mode 100644 packages/ui/components/AsyncInput.tsx create mode 100644 packages/ui/components/Radio.tsx diff --git a/apps/agent/next.config.js b/apps/agent/next.config.js index 7ee104e6..72e70b21 100644 --- a/apps/agent/next.config.js +++ b/apps/agent/next.config.js @@ -1,7 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - transpilePackages: ['@sahil/lib', 'ui', '@sahil/configs'], + transpilePackages: ['@sahil/lib', 'ui', '@sahil/configs', "@sahil/features"], images: { remotePatterns: [ { diff --git a/apps/agent/package.json b/apps/agent/package.json index 16e294c0..10f75b45 100644 --- a/apps/agent/package.json +++ b/apps/agent/package.json @@ -17,6 +17,7 @@ "@react-google-maps/api": "^2.19.2", "@sahil/configs": "*", "@sahil/lib": "*", + "@sahil/features": "*", "apollo-link-ws": "^1.0.20", "autoprefixer": "10.4.15", "daisyui": "3.5.1", diff --git a/apps/agent/src/Businesses/AddNewBusiness.tsx b/apps/agent/src/Businesses/AddNewBusiness.tsx deleted file mode 100644 index 7ded00d0..00000000 --- a/apps/agent/src/Businesses/AddNewBusiness.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useForm, SubmitHandler } from "react-hook-form"; -import { useRegisterBusiness } from "@/hooks/businesses"; -import { z } from "zod"; - -type Inputs = { - businessName: string; - businessType: string; -}; - -const businessSchema = z.object({ - businessName: z.string(), - businessType: z.string(), -}); - -export const InsertNewBusiness = () => { - const { - register, - handleSubmit, - watch, - formState: { errors }, - } = useForm(); - const { insertClient, loading, error } = useRegisterBusiness(); - const onSubmit: SubmitHandler = (data) => { - const validtedInput = businessSchema.parse(data); - - insertClient({ - variables: { - object: { - name: data.businessName, - ...data, - }, - }, - }); - }; - return ( -
-
- -
-
- -
- -
- ); -}; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx similarity index 79% rename from apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx rename to apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx index 14efb6ff..a71af874 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx @@ -10,12 +10,12 @@ const businessAddressSchema = z.object({ type FormData = z.infer; -export const AddressInfo = () => { +export const BusinessAddressInfo = () => { const onSubmit: SubmitHandler = async (data) => { const validatedInput = businessAddressSchema.parse(data); }; return ( - + { placeholder="Keji's Foods" /> + + +
diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx index 8cf16310..e7929a00 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { useBusinessFormStore } from "@/hooks/useBusinessFormStore"; -import { Card, FormControl } from "ui"; +import { Card, Input, FormControl } from "ui"; import { HiArrowSmallLeft, HiArrowSmallRight } from "react-icons/hi2"; const businessInfoSchema = z.object({ @@ -36,15 +36,15 @@ export const BusinessInfo = () => { - + diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx index b7ef9829..8d91971d 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx @@ -1,10 +1,11 @@ +import { Card } from "ui"; // import { useRegisterBusiness, useBusinessValidated } from "@/hooks/businesses"; // async refine to check whether entry exists or not export const BusinessInfoSummary = () => { return ( -
-

Summary

-
+ +

Summary

+
); }; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx index 501515a0..852d3a46 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx @@ -1,22 +1,78 @@ -import { Business } from "@sahil/lib/graphql/__generated__/graphql"; -import { Card, FormControl } from "ui"; -import { HiArrowSmallLeft, HiArrowSmallRight } from "react-icons/hi2"; +import { useForm, SubmitHandler } from "react-hook-form"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Card, Input, Radio, Select } from "ui"; +import { + HiOutlineCreditCard, + HiOutlineBanknotes, + HiArrowSmallRight, +} from "react-icons/hi2"; + +const businessPreferencesSchema = z.object({ + preferredContactMethod: z.string(), + preferredPaymentMethod: z.string(), +}); + +type FormData = z.infer; export const BusinessPreferencesInfo = () => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + // @ts-ignore + resolver: zodResolver(businessPreferencesSchema), + }); + + const onSubmit: SubmitHandler = async (data) => {}; return ( - -

Business Preferences

- - + + - -
- - -
-
+
+ +
+
+ + +
+
+ + +
+ + ); }; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx index 8411d5ac..aa18e296 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/index.tsx @@ -1,4 +1,4 @@ -export * from "./AddressInfo"; +export * from "./BusinessAddressInfo"; export * from "./BusinessInfo"; export * from "./BusinessInfoSummary"; export * from "./BusinessFormSteps"; diff --git a/apps/agent/src/Orders/OrderProcessingForm/PaymentDetails.tsx b/apps/agent/src/Orders/OrderProcessingForm/PaymentDetails.tsx index 9cb1029b..4d6ba3bc 100644 --- a/apps/agent/src/Orders/OrderProcessingForm/PaymentDetails.tsx +++ b/apps/agent/src/Orders/OrderProcessingForm/PaymentDetails.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { useOrderFormStore } from "@/hooks/useOrderFormStore"; -import { Card } from "ui"; +import { Card, Radio } from "ui"; import { HiXMark, HiOutlineCreditCard, diff --git a/apps/agent/src/pages/businesses/register/[...step].tsx b/apps/agent/src/pages/businesses/register/[...step].tsx index 15fdc6df..93a7b27e 100644 --- a/apps/agent/src/pages/businesses/register/[...step].tsx +++ b/apps/agent/src/pages/businesses/register/[...step].tsx @@ -3,7 +3,7 @@ import { z } from "zod"; import { useBusinessFormStore } from "@/hooks/useBusinessFormStore"; import { useParams, usePathname, useRouter } from "next/navigation"; import { - AddressInfo, + BusinessAddressInfo, BusinessInfo, BusinessInfoSummary, BusinessFormSteps, @@ -92,7 +92,7 @@ export default function BusinessRegistrationPage() { onNextStep={onNextStep} /> {currentStep === "business_info" && } - {currentStep === "address_info" && } + {currentStep === "address_info" && } {currentStep === "preferences" && } {currentStep === "summary" && }
diff --git a/apps/client/next.config.js b/apps/client/next.config.js index 7ee104e6..72e70b21 100644 --- a/apps/client/next.config.js +++ b/apps/client/next.config.js @@ -1,7 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - transpilePackages: ['@sahil/lib', 'ui', '@sahil/configs'], + transpilePackages: ['@sahil/lib', 'ui', '@sahil/configs', "@sahil/features"], images: { remotePatterns: [ { diff --git a/apps/client/package.json b/apps/client/package.json index b81e1f88..d918ae3d 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -14,7 +14,8 @@ "next": "14.0.1", "ui": "*", "@sahil/lib": "*", - "@sahil/configs": "*" + "@sahil/configs": "*", + "@sahil/features": "*" }, "devDependencies": { "typescript": "^5", diff --git a/apps/client/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx b/apps/client/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx index 94a866cd..8af96213 100644 --- a/apps/client/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx +++ b/apps/client/src/Businesses/BusinessRegistrationForm/AddressInfo.tsx @@ -1,4 +1,4 @@ -export const AddressInfo = () => { +export const BusinessAddressInfo = () => { return (

Address Info

diff --git a/apps/client/src/Businesses/BusinessRegistrationForm/index.tsx b/apps/client/src/Businesses/BusinessRegistrationForm/index.tsx index 4d232227..b773edd8 100644 --- a/apps/client/src/Businesses/BusinessRegistrationForm/index.tsx +++ b/apps/client/src/Businesses/BusinessRegistrationForm/index.tsx @@ -1,4 +1,4 @@ -export * from "./AddressInfo"; +export * from "./BusinessAddressInfo"; export * from "./BusinessInfo"; export * from "./BusinessInfoSummary"; export * from "./BusinessFormSteps"; diff --git a/packages/eslint-config-custom/index.js b/packages/eslint-config-custom/index.js index c9523f13..3e80375e 100644 --- a/packages/eslint-config-custom/index.js +++ b/packages/eslint-config-custom/index.js @@ -1,5 +1,5 @@ module.exports = { - extends: ["next", "turbo", "prettier"], + extends: ["next", "prettier", "next/core-web-vitals"], rules: { "@next/next/no-html-link-for-pages": "off", }, diff --git a/packages/features/businesses/BusinessOrderHistory.tsx b/packages/features/businesses/BusinessOrderHistory.tsx new file mode 100644 index 00000000..60e50f87 --- /dev/null +++ b/packages/features/businesses/BusinessOrderHistory.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export const BusinessOrderHistory = ({ business }) => { + return

Hello, World!

; +}; diff --git a/packages/features/businesses/zod-schema.ts b/packages/features/businesses/zod-schema.ts new file mode 100644 index 00000000..c9c5ebae --- /dev/null +++ b/packages/features/businesses/zod-schema.ts @@ -0,0 +1,18 @@ +import { z } from "zod"; + +export const businessSchema = z.object({ + name: z.string().trim(), + // type: z.string(), + // description: z.string(), + // contactEmail: z.string(), + // contactName: z.string(), + // preferredContactMethod: z.string(), + // preferredDeliveryMethod: z.string() + // price: z + // .string() + // .min(1, { message: "required" }) + // .transform((value) => +value) + // .refine((value) => !isNaN(value), { message: "Must be a number"}) +}); + +export type BusinessAttributes = z.infer; diff --git a/packages/features/package.json b/packages/features/package.json new file mode 100644 index 00000000..e14146a3 --- /dev/null +++ b/packages/features/package.json @@ -0,0 +1,10 @@ +{ + "name": "@sahil/features", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@sahil/lib": "*", + "@sahil/configs": "*" + } +} diff --git a/packages/ui/components/AsyncInput.tsx b/packages/ui/components/AsyncInput.tsx new file mode 100644 index 00000000..e2835efd --- /dev/null +++ b/packages/ui/components/AsyncInput.tsx @@ -0,0 +1,38 @@ +import React, { useState, useEffect } from "react"; + +const AsyncInput = ({ onFetch }) => { + const [inputValue, setInputValue] = useState(""); + const [suggestions, setSuggestions] = useState([]); + + useEffect(() => { + const fetchSuggestions = async () => { + if (!inputValue) return; + try { + const response = await onFetch(inputValue); + setSuggestions(response); + } catch (error) { + console.error("Failed to fetch suggestions:", error); + } + }; + + fetchSuggestions(); + }, [inputValue, onFetch]); + + return ( +
+ setInputValue(event.target.value)} + /> +
    + {suggestions.map((suggestion, index) => ( +
  • {suggestion}
  • + ))} +
+
+ ); +}; + +export default AsyncInput; diff --git a/packages/ui/components/Radio.tsx b/packages/ui/components/Radio.tsx new file mode 100644 index 00000000..d168cc89 --- /dev/null +++ b/packages/ui/components/Radio.tsx @@ -0,0 +1,21 @@ +import { Icon } from "./Icon"; + +export const Radio = ({ label, icon, name, register, errors }) => { + return ( +
+ +
+ ); +}; diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx index 98b44950..8834657d 100644 --- a/packages/ui/index.tsx +++ b/packages/ui/index.tsx @@ -18,6 +18,7 @@ export * from "./components/Stats"; export * from "./components/Select"; export * from "./components/Steps"; export * from "./components/Modal"; +export * from "./components/Radio"; export * from "./components/Tabs"; export * from "./components/Toggle"; export * from "./components/Wrapper"; From 49c7118d11e44d7682bcc8dc5af8e6ef147aef44 Mon Sep 17 00:00:00 2001 From: Eman Date: Thu, 25 Jan 2024 18:13:38 +0300 Subject: [PATCH 09/11] feat: improve business registration workflow --- apps/agent/package.json | 3 +- .../src/Businesses/BusinessOverviewCard.tsx | 12 +- .../BusinessAddressInfo.tsx | 71 ++++++---- .../BusinessRegistrationForm/BusinessInfo.tsx | 46 ++++--- .../BusinessInfoSummary.tsx | 122 +++++++++++++++++- .../BusinessPreferencesInfo.tsx | 55 +++++++- apps/agent/src/hooks/businesses.ts | 18 ++- .../businesses/operations/registerBusiness.ts | 4 +- packages/lib/graphql/mutations/businesses.ts | 11 +- packages/lib/graphql/mutations/users.ts | 7 +- .../lib/graphql/subscriptions/businesses.ts | 4 +- packages/ui/components/Navbar.tsx | 31 +++++ packages/ui/components/Spinner.tsx | 3 + packages/ui/index.tsx | 1 + 14 files changed, 311 insertions(+), 77 deletions(-) create mode 100644 packages/ui/components/Spinner.tsx diff --git a/apps/agent/package.json b/apps/agent/package.json index 10f75b45..414d425f 100644 --- a/apps/agent/package.json +++ b/apps/agent/package.json @@ -16,8 +16,8 @@ "@hookform/resolvers": "^3.3.0", "@react-google-maps/api": "^2.19.2", "@sahil/configs": "*", - "@sahil/lib": "*", "@sahil/features": "*", + "@sahil/lib": "*", "apollo-link-ws": "^1.0.20", "autoprefixer": "10.4.15", "daisyui": "3.5.1", @@ -26,6 +26,7 @@ "eslint-config-next": "13.4.16", "graphql": "^16.8.0", "graphql-ws": "^5.14.0", + "jsonwebtoken": "^9.0.2", "next": "13.4.16", "next-auth": "^4.23.1", "postcss": "8.4.28", diff --git a/apps/agent/src/Businesses/BusinessOverviewCard.tsx b/apps/agent/src/Businesses/BusinessOverviewCard.tsx index 2fa5d516..7d70baab 100644 --- a/apps/agent/src/Businesses/BusinessOverviewCard.tsx +++ b/apps/agent/src/Businesses/BusinessOverviewCard.tsx @@ -27,7 +27,7 @@ type Props = { export const BusinessOverviewCard: FC = ({ business }) => { return ( -
+
= ({ business }) => { {business.name}
-
+
- + Business Type

{business.type}

- Contact Name + Contact Name

{business.contactName}

@@ -66,7 +66,7 @@ export const BusinessOverviewCard: FC = ({ business }) => { {business.addresses && business.addresses.map((address, index) => (
- +

{address.street_address}

@@ -75,7 +75,7 @@ export const BusinessOverviewCard: FC = ({ business }) => {
- +

{business.phoneNumber}

diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx index a71af874..224059fa 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessAddressInfo.tsx @@ -1,8 +1,10 @@ import { useForm, SubmitHandler } from "react-hook-form"; import { useRouter } from "next/router"; import { z } from "zod"; -import { Card, FormControl } from "ui"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Card, FormControl, Input } from "ui"; import { HiArrowSmallLeft, HiArrowSmallRight } from "react-icons/hi2"; +import { useBusinessFormStore } from "@/hooks/useBusinessFormStore"; const businessAddressSchema = z.object({ streetName: z.string().min(2, { message: "Must be more than 2 characters" }), @@ -11,36 +13,55 @@ const businessAddressSchema = z.object({ type FormData = z.infer; export const BusinessAddressInfo = () => { + const { formData, goToStep, updateStepFormData } = useBusinessFormStore( + (state) => state + ); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + // @ts-ignore + resolver: zodResolver(businessAddressSchema), + }); + + const router = useRouter(); const onSubmit: SubmitHandler = async (data) => { const validatedInput = businessAddressSchema.parse(data); + updateStepFormData(validatedInput); + goToStep("next"); + router.push(`/businesses/register/preferences`); }; return ( - - - + + - - - - - - - -
- - -
-
+
+ + +
+ + ); }; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx index e7929a00..1463a243 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfo.tsx @@ -3,11 +3,14 @@ import { useRouter } from "next/router"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { useBusinessFormStore } from "@/hooks/useBusinessFormStore"; -import { Card, Input, FormControl } from "ui"; -import { HiArrowSmallLeft, HiArrowSmallRight } from "react-icons/hi2"; +import { Card, Input } from "ui"; +import { HiArrowSmallRight } from "react-icons/hi2"; const businessInfoSchema = z.object({ name: z.string().min(2, { message: "Must be more than 2 characters" }), + businessType: z + .string() + .min(2, { message: "Must be more than 2 characters" }), }); type FormData = z.infer; @@ -25,29 +28,34 @@ export const BusinessInfo = () => { const router = useRouter(); - const { formData } = useBusinessFormStore((state) => state); + const { goToStep, updateStepFormData } = useBusinessFormStore( + (state) => state + ); + const onSubmit: SubmitHandler = async (data) => { const validatedInput = businessInfoSchema.parse(data); + updateStepFormData(validatedInput); + goToStep("next"); + router.push(`/businesses/register/address_info`); }; + return (
- - - - - - + +
diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx index 8d91971d..e23075d4 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx @@ -1,11 +1,121 @@ -import { Card } from "ui"; -// import { useRegisterBusiness, useBusinessValidated } from "@/hooks/businesses"; +import { useState } from "react"; +import { Card, Spinner, FormControl } from "ui"; +import { HiArrowSmallRight, HiOutlineCheckCircle } from "react-icons/hi2"; +import { useRouter } from "next/router"; +import toast, { Toaster } from "react-hot-toast"; +import { + useRegisterBusiness, + useRegisterBusinessSubscription, +} from "@/hooks/businesses"; +import { useBusinessFormStore } from "@/hooks/useBusinessFormStore"; -// async refine to check whether entry exists or not export const BusinessInfoSummary = () => { + const [actionId, setActionId] = useState(""); + const { formData } = useBusinessFormStore((state) => state); + const router = useRouter(); + + const { data, loading: subscriptionLoading } = + useRegisterBusinessSubscription(actionId); + + const { error, loading, registerBusinessAction } = useRegisterBusiness(); + const onSubmit = async () => { + const business = await registerBusinessAction({ + variables: { + object: { + name: formData.name, + }, + }, + }); + setActionId(business?.data?.registerBusinessAction); + router.push(`/businesses/${data?.output?.id}`); + }; + + if (error) { + toast.error("This didn't work."); + } return ( - -

Summary

-
+ <> +
+ + +
+ + + + +
+
+ {formData.businessType && ( + +
+ + + + +
+
+ )} +
+ + +
+ + + + +
+
+
+ + +
+ + + + +
+
+ { formData.preferredPaymentMethod && +
+ + + + +
+
} + +
+
+ + {loading ? : } +
+
+ + ); }; diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx index 852d3a46..cd756110 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessPreferencesInfo.tsx @@ -1,11 +1,16 @@ +import { useRouter } from "next/router"; import { useForm, SubmitHandler } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Card, Input, Radio, Select } from "ui"; +import { useBusinessFormStore } from "@/hooks/useBusinessFormStore"; + import { HiOutlineCreditCard, HiOutlineBanknotes, HiArrowSmallRight, + HiOutlineBuildingOffice, + HiOutlineMapPin, } from "react-icons/hi2"; const businessPreferencesSchema = z.object({ @@ -16,6 +21,10 @@ const businessPreferencesSchema = z.object({ type FormData = z.infer; export const BusinessPreferencesInfo = () => { + const { formData, goToStep, updateStepFormData } = useBusinessFormStore( + (state) => state + ); + const router = useRouter(); const { register, handleSubmit, @@ -25,10 +34,15 @@ export const BusinessPreferencesInfo = () => { resolver: zodResolver(businessPreferencesSchema), }); - const onSubmit: SubmitHandler = async (data) => {}; + const onSubmit: SubmitHandler = async (data) => { + const validatedInput = businessPreferencesSchema.parse(data); + updateStepFormData(validatedInput); + goToStep("next"); + router.push(`/businesses/register/summary`); + }; return ( - - + + { errors={errors} />
+
+ + +

+ How do you prefer to receive notifications? +

{ errors={errors} />
-
- - + + + +

+ How do you prefer to receive notifications? +

+
+ +
+ +
+ + +
); }; diff --git a/apps/agent/src/hooks/businesses.ts b/apps/agent/src/hooks/businesses.ts index dc9fd5ba..46eef133 100644 --- a/apps/agent/src/hooks/businesses.ts +++ b/apps/agent/src/hooks/businesses.ts @@ -1,12 +1,15 @@ -import { useMutation, useQuery } from "@apollo/client"; +import { useMutation, useQuery, useSubscription } from "@apollo/client"; import { FETCH_BUSINESSES, FETCH_BUSINESS_BY_PK, FETCH_BUSINESS_ORDERS, INSERT_NEW_BUSINESS, + REGISTER_BUSINESS_ACTION, } from "@sahil/lib/graphql"; +import { BUSINESS_VALIDATED } from "@sahil/lib/graphql/subscriptions/businesses"; + // graphql types import { GetBusinessByPkQuery, @@ -38,10 +41,17 @@ export const useFetchBusinesses = () => { }; export const useRegisterBusiness = () => { - const [insertClient, { data, loading, error }] = - useMutation(INSERT_NEW_BUSINESS); + const [registerBusinessAction, { data, loading, error }] = useMutation( + REGISTER_BUSINESS_ACTION + ); + return { data: data?.registerBusinessAction, loading, registerBusinessAction, error }; +}; - return { loading, insertClient, error }; +export const useRegisterBusinessSubscription = (id: string) => { + const { data, loading } = useSubscription(BUSINESS_VALIDATED, { + variables: { id }, + }); + return { data: data?.registerBusinessAction, loading }; }; export const useFetchBusinessOrders = ({ diff --git a/apps/api/src/businesses/operations/registerBusiness.ts b/apps/api/src/businesses/operations/registerBusiness.ts index a3dad9c1..c2445193 100644 --- a/apps/api/src/businesses/operations/registerBusiness.ts +++ b/apps/api/src/businesses/operations/registerBusiness.ts @@ -12,7 +12,7 @@ export const businessSchema = z.object({ // type: z.string(), // description: z.string(), // contactEmail: z.string(), - // contactName: z.string(), + contactName: z.string(), // preferredContactMethod: z.string(), // preferredDeliveryMethod: z.string() // price: z @@ -31,5 +31,5 @@ export const registerBusiness = async ( object: business, }); // @ts-ignore - return data?.insert_business_one; + return Promise.resolve(data?.insert_business_one); }; diff --git a/packages/lib/graphql/mutations/businesses.ts b/packages/lib/graphql/mutations/businesses.ts index a9638236..d9b339da 100644 --- a/packages/lib/graphql/mutations/businesses.ts +++ b/packages/lib/graphql/mutations/businesses.ts @@ -1,14 +1,23 @@ import { gql } from "@apollo/client"; export const INSERT_NEW_BUSINESS = gql` - mutation registerClient($object: business_insert_input!) { + mutation registerBusiness($object: business_insert_input) { insert_business_one(object: $object) { id name + contactName } } `; +export const REGISTER_BUSINESS_ACTION = gql` + mutation registerBusinessAction( + $object: RegisterBusinessActionBusinessInsertInput! + ) { + registerBusinessAction(object: $object) + } +`; + export const INSERT_BUSINESS_ADDRESS = gql` mutation insertBusinessAddress($object: addresses_insert_input!) { insert_addresses_one(object: $object) { diff --git a/packages/lib/graphql/mutations/users.ts b/packages/lib/graphql/mutations/users.ts index ca8f65cf..018b9905 100644 --- a/packages/lib/graphql/mutations/users.ts +++ b/packages/lib/graphql/mutations/users.ts @@ -1,10 +1,7 @@ import { gql } from "@apollo/client"; export const INSERT_NEW_USER = gql` - mutation registerUser($object: users_insert_input!) { - insert_users_one(object: $object) { - id - name - } + mutation registerUserAction($object: RegisterUserActionUsersInsertInput!) { + registerUserAction(object: $object) } `; diff --git a/packages/lib/graphql/subscriptions/businesses.ts b/packages/lib/graphql/subscriptions/businesses.ts index 478cda81..90e1c340 100644 --- a/packages/lib/graphql/subscriptions/businesses.ts +++ b/packages/lib/graphql/subscriptions/businesses.ts @@ -1,8 +1,8 @@ import { gql } from "@apollo/client"; export const BUSINESS_VALIDATED = gql` - subscription MySubscription { - registerBusinessAction(id: "a9872403-36db-4423-ab05-b8d1d4dec326") { + subscription registerBusinessActionSubscription($id: uuid!) { + registerBusinessAction(id: $id) { created_at errors id diff --git a/packages/ui/components/Navbar.tsx b/packages/ui/components/Navbar.tsx index 13ac8124..81016194 100644 --- a/packages/ui/components/Navbar.tsx +++ b/packages/ui/components/Navbar.tsx @@ -98,6 +98,37 @@ export const Navbar: FC = ({ links, logo, header = "Sahil" }) => { })}
+
+
+
+ Tailwind CSS Navbar component +
+
+ +
); diff --git a/packages/ui/components/Spinner.tsx b/packages/ui/components/Spinner.tsx new file mode 100644 index 00000000..38204f6a --- /dev/null +++ b/packages/ui/components/Spinner.tsx @@ -0,0 +1,3 @@ +export const Spinner = () => { + return ; +}; diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx index 8834657d..870725ee 100644 --- a/packages/ui/index.tsx +++ b/packages/ui/index.tsx @@ -19,6 +19,7 @@ export * from "./components/Select"; export * from "./components/Steps"; export * from "./components/Modal"; export * from "./components/Radio"; +export * from "./components/Spinner"; export * from "./components/Tabs"; export * from "./components/Toggle"; export * from "./components/Wrapper"; From 984043c282da1f3c84de871239b4470e098f3a5d Mon Sep 17 00:00:00 2001 From: Eman Date: Thu, 25 Jan 2024 18:15:30 +0300 Subject: [PATCH 10/11] chore: yarn format --- .../src/Businesses/BusinessOverviewCard.tsx | 4 +- .../BusinessInfoSummary.tsx | 29 ++++----- apps/agent/src/hooks/businesses.ts | 7 ++- .../pages/businesses/register/[...step].tsx | 6 +- yarn.lock | 63 +++++++++++++++++++ 5 files changed, 88 insertions(+), 21 deletions(-) diff --git a/apps/agent/src/Businesses/BusinessOverviewCard.tsx b/apps/agent/src/Businesses/BusinessOverviewCard.tsx index 7d70baab..d1111b1d 100644 --- a/apps/agent/src/Businesses/BusinessOverviewCard.tsx +++ b/apps/agent/src/Businesses/BusinessOverviewCard.tsx @@ -57,7 +57,9 @@ export const BusinessOverviewCard: FC = ({ business }) => {

{business.type}

- Contact Name + + Contact Name +

{business.contactName}

diff --git a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx index e23075d4..dae6e855 100644 --- a/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx +++ b/apps/agent/src/Businesses/BusinessRegistrationForm/BusinessInfoSummary.tsx @@ -95,20 +95,21 @@ export const BusinessInfoSummary = () => {
- { formData.preferredPaymentMethod && -
- - - - -
-
} - + {formData.preferredPaymentMethod && ( + +
+ + + + +
+
+ )}
diff --git a/apps/agent/src/hooks/businesses.ts b/apps/agent/src/hooks/businesses.ts index 46eef133..2e97ebe0 100644 --- a/apps/agent/src/hooks/businesses.ts +++ b/apps/agent/src/hooks/businesses.ts @@ -44,7 +44,12 @@ export const useRegisterBusiness = () => { const [registerBusinessAction, { data, loading, error }] = useMutation( REGISTER_BUSINESS_ACTION ); - return { data: data?.registerBusinessAction, loading, registerBusinessAction, error }; + return { + data: data?.registerBusinessAction, + loading, + registerBusinessAction, + error, + }; }; export const useRegisterBusinessSubscription = (id: string) => { diff --git a/apps/agent/src/pages/businesses/register/[...step].tsx b/apps/agent/src/pages/businesses/register/[...step].tsx index 93a7b27e..9de62d36 100644 --- a/apps/agent/src/pages/businesses/register/[...step].tsx +++ b/apps/agent/src/pages/businesses/register/[...step].tsx @@ -67,13 +67,9 @@ export default function BusinessRegistrationPage() { router.push(`/businesses/register/${steps[currentIndex + 1]}`); }; - const navigateToNextStep = (path: string) => { - goToStep("next"); - router.push(`/businesses/register/${path}`); - }; return (
-
+

Register New Business

diff --git a/yarn.lock b/yarn.lock index e5356cf0..40d7a7f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5884,6 +5884,22 @@ jsonify@^0.0.1: resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" @@ -5894,6 +5910,15 @@ jsonify@^0.0.1: object.assign "^4.1.4" object.values "^1.1.6" +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + jwa@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" @@ -5903,6 +5928,14 @@ jwa@^2.0.0: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + jws@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" @@ -6001,21 +6034,51 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + lodash.isarguments@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" From 3e4e9eb3ce09c1736c9510c99dec8571d3a67a61 Mon Sep 17 00:00:00 2001 From: Eman Date: Thu, 25 Jan 2024 18:24:27 +0300 Subject: [PATCH 11/11] feat: validate business registration --- .../businesses/operations/registerBusiness.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/api/src/businesses/operations/registerBusiness.ts b/apps/api/src/businesses/operations/registerBusiness.ts index c2445193..9766f9d5 100644 --- a/apps/api/src/businesses/operations/registerBusiness.ts +++ b/apps/api/src/businesses/operations/registerBusiness.ts @@ -9,17 +9,12 @@ type DeliveryMethod = "pick-up-location" | "direct-delivery"; export const businessSchema = z.object({ name: z.string().trim(), - // type: z.string(), - // description: z.string(), - // contactEmail: z.string(), - contactName: z.string(), - // preferredContactMethod: z.string(), - // preferredDeliveryMethod: z.string() - // price: z - // .string() - // .min(1, { message: "required" }) - // .transform((value) => +value) - // .refine((value) => !isNaN(value), { message: "Must be a number"}) + type: z.string(), + description: z.string().optional(), + contactEmail: z.string().optional(), + contactName: z.string().optional(), + preferredContactMethod: z.string().optional(), + preferredDeliveryMethod: z.string().optional(), }); export type BusinessAttributes = z.infer;