Refactoring

This commit is contained in:
Darren Clarke 2024-04-29 17:27:25 +02:00
parent 39cfada3e8
commit dd14dfe72e
41 changed files with 866 additions and 742 deletions

View file

@ -3,10 +3,10 @@
import { FC } from "react";
import { useFormState } from "react-dom";
import { Grid } from "@mui/material";
import { TextField } from "ui";
import { TextField, Select, MultiValueField } from "ui";
import { Create as InternalCreate } from "@/app/_components/Create";
import { generateCreateAction } from "@/app/_lib/actions";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
import { FieldDescription } from "@/app/_lib/service";
type CreateProps = {
@ -15,8 +15,18 @@ type CreateProps = {
export const Create: FC<CreateProps> = ({ service }) => {
const {
[service]: { entity, table, displayName, createFields: fields },
[service]: { entity, table, displayName, createFields },
} = serviceConfig;
const fields = createFields.map((field: any) => {
const copy = { ...field };
Object.keys(copy).forEach((key: any) => {
if (typeof copy[key] === "function") {
delete copy[key];
}
});
return copy;
});
const createAction = generateCreateAction({ entity, table, fields });
const initialState = {
message: null,
@ -39,18 +49,37 @@ export const Create: FC<CreateProps> = ({ service }) => {
formState={formState}
>
<Grid container direction="row" rowSpacing={3} columnSpacing={2}>
{fields.map(
{createFields.map(
(field) =>
!field.hidden && (
<Grid key={field.name} item xs={field.size ?? 6}>
<TextField
name={field.name}
label={field.label}
lines={field.lines ?? 1}
required={field.required ?? false}
formState={formState}
helperText={field.helperText}
/>
{field.kind === "select" && (
<Select
name={field.name}
label={field.label}
required={field.required ?? false}
formState={formState}
getOptions={field.getOptions}
/>
)}
{field.kind === "multi" && (
<MultiValueField
name={field.name}
label={field.label}
formState={formState}
helperText={field.helperText}
/>
)}
{(!field.kind || field.kind === "text") && (
<TextField
name={field.name}
label={field.label}
lines={field.lines ?? 1}
required={field.required ?? false}
formState={formState}
helperText={field.helperText}
/>
)}
</Grid>
),
)}

View file

@ -7,7 +7,7 @@ import { Selectable } from "kysely";
import { Database } from "@/app/_lib/database";
import { Detail as InternalDetail } from "@/app/_components/Detail";
import { generateDeleteAction } from "@/app/_lib/actions";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
type DetailProps = {
service: string;

View file

@ -1,5 +1,5 @@
import { db } from "@/app/_lib/database";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
import { Detail } from "./_components/Detail";
type Props = {

View file

@ -8,7 +8,7 @@ import { Selectable } from "kysely";
import { Database } from "@/app/_lib/database";
import { Edit as InternalEdit } from "@/app/_components/Edit";
import { generateUpdateAction } from "@/app/_lib/actions";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
type EditProps = {
service: string;

View file

@ -1,5 +1,5 @@
import { db } from "@/app/_lib/database";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
import { Edit } from "./_components/Edit";
type PageProps = {

View file

@ -4,7 +4,7 @@ import { FC } from "react";
import { List as InternalList } from "@/app/_components/List";
import type { Selectable } from "kysely";
import { Database } from "@/app/_lib/database";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
type ListProps = {
service: string;

View file

@ -1,6 +1,6 @@
import { List } from "./_components/List";
import { db } from "@/app/_lib/database";
import { serviceConfig } from "@/app/_lib/config";
import { serviceConfig } from "@/app/_config/config";
type PageProps = {
params: {
@ -11,7 +11,12 @@ type PageProps = {
export default async function Page({ params: { segment } }: PageProps) {
const service = segment[0];
if (!service) return null;
const config = serviceConfig[service];
if (!config) return null;
const rows = await db.selectFrom(config.table).selectAll().execute();
return <List service={service} rows={rows} />;

View file

@ -28,6 +28,7 @@ export const createAction = async ({
currentState,
formData,
}: CreateActionArgs) => {
console.log(formData);
const newRecord = fields.reduce(
(acc: Record<string, any>, field: FieldDescription) => {
if (field.autogenerated === "token") {
@ -41,13 +42,19 @@ export const createAction = async ({
{},
);
await db.insertInto(table).values(newRecord).execute();
console.log({ newRecord });
const record = await db
.insertInto(table)
.values(newRecord)
.returning(["id"])
.executeTakeFirstOrThrow();
console.log({ record });
revalidatePath(`/${entity}`);
return {
...currentState,
values: newRecord,
values: { ...newRecord, id: record.id },
success: true,
};
};
@ -104,3 +111,7 @@ export const deleteAction = async ({ entity, table, id }: DeleteActionArgs) => {
return true;
};
export const selectAllAction = async (table: keyof Database) => {
return db.selectFrom(table).selectAll().execute();
};

View file

@ -24,7 +24,7 @@ export const Create: FC<CreateProps> = ({
useEffect(() => {
if (formState.success) {
router.back();
router.push(`/${entity}/${formState.values.id}`);
}
}, [formState.success, router]);

View file

@ -1,4 +1,4 @@
import type { ServiceConfig } from "./service";
import type { ServiceConfig } from "@/app/_lib/service";
import { facebookConfig as facebook } from "./facebook";
import { signalConfig as signal } from "./signal";
import { whatsappConfig as whatsapp } from "./whatsapp";

View file

@ -0,0 +1,123 @@
import { Service, ServiceConfig } from "@/app/_lib/service";
export const facebookConfig: ServiceConfig = {
entity: "facebook",
table: "FacebookBot",
displayName: "Facebook Connection",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{ name: "appId", label: "App ID", required: true },
{ name: "appSecret", label: "App Secret", required: true },
{ name: "pageId", label: "Page ID", required: true },
{
name: "pageAccessToken",
label: "Page Access Token",
required: true,
},
{
name: "token",
label: "Token",
hidden: true,
required: true,
autogenerated: "token",
},
{
name: "verifyToken",
label: "Verify Token",
hidden: true,
required: true,
autogenerated: "token",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "token",
label: "Token",
disabled: true,
refreshable: true,
},
{
name: "verifyToken",
label: "Verify Token",
disabled: true,
refreshable: true,
},
{ name: "appId", label: "App ID", required: true },
{ name: "appSecret", label: "App Secret", required: true },
{ name: "pageId", label: "Page ID", required: true },
{
name: "pageAccessToken",
label: "Page Access Token",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
required: true,
size: 12,
},
{
name: "token",
label: "Token",
copyable: true,
},
{
name: "verifyToken",
label: "Verify Token",
copyable: true,
},
{ name: "appId", label: "App ID", required: true },
{ name: "appSecret", label: "App Secret", required: true },
{
name: "pageId",
label: "Page ID",
required: true,
copyable: true,
},
{
name: "pageAccessToken",
label: "Page Access Token",
required: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};

View file

@ -0,0 +1,86 @@
import { ServiceConfig } from "@/app/_lib/service";
export const signalConfig: ServiceConfig = {
entity: "signal",
table: "SignalBot",
displayName: "Signal Connection",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "phoneNumber",
label: "phoneNumber",
required: true,
},
{
name: "token",
label: "Token",
hidden: true,
required: true,
autogenerated: "token",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "phoneNumber",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "phoneNumber",
},
{
name: "token",
label: "Token",
copyable: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "phoneNumber",
headerName: "Phone Number",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};

View file

@ -1,4 +1,4 @@
import { ServiceConfig } from "./service";
import { ServiceConfig } from "@/app/_lib/service";
export const usersConfig: ServiceConfig = {
entity: "users",

View file

@ -1,9 +1,9 @@
import { ServiceConfig } from "./service";
import { ServiceConfig } from "@/app/_lib/service";
export const webhooksConfig: ServiceConfig = {
entity: "webhooks",
table: "Webhook",
displayName: "Webhook",
export const voiceConfig: ServiceConfig = {
entity: "voice",
table: "VoiceLine",
displayName: "Voice Line",
createFields: [
{
name: "name",
@ -17,6 +17,11 @@ export const webhooksConfig: ServiceConfig = {
size: 12,
lines: 3,
},
{
name: "phoneNumber",
label: "phoneNumber",
required: true,
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
@ -26,6 +31,11 @@ export const webhooksConfig: ServiceConfig = {
required: true,
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
@ -35,6 +45,11 @@ export const webhooksConfig: ServiceConfig = {
required: true,
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
],
listColumns: [
{
@ -42,6 +57,11 @@ export const webhooksConfig: ServiceConfig = {
headerName: "Name",
flex: 1,
},
{
field: "phoneNumber",
headerName: "Phone Number",
flex: 1,
},
{
field: "description",
headerName: "Description",

View file

@ -0,0 +1,125 @@
import { selectAllAction } from "@/app/_actions/service";
import { ServiceConfig } from "@/app/_lib/service";
const tableLookup = {
whatsapp: "WhatsappBot",
facebook: "FacebookBot",
signal: "SignalBot",
};
export const webhooksConfig: ServiceConfig = {
entity: "webhooks",
table: "Webhook",
displayName: "Webhook",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "httpMethod",
label: "HTTP Method",
kind: "select",
getOptions: async () => [
{ value: "post", label: "POST" },
{ value: "put", label: "PUT" },
],
defaultValue: "post",
required: true,
size: 2,
},
{
name: "endpointUrl",
label: "Endpoint",
required: true,
size: 10,
},
{
name: "backendType",
label: "Backend Type",
kind: "select",
getOptions: async (_formState: any) => [
{ value: "whatsapp", label: "WhatsApp" },
{ value: "facebook", label: "Facebook" },
{ value: "signal", label: "Signal" },
],
defaultValue: "facebook",
required: true,
},
{
name: "backendId",
label: "Backend ID",
kind: "select",
getOptions: async (formState: any) => {
console.log({ formState });
if (!formState || !formState.values.backendType) {
return [];
}
// @ts-expect-error
const table = tableLookup[formState.values.backendType];
console.log({ table });
const result = await selectAllAction(table);
console.log({ result });
return result.map((item: any) => ({
value: item.id,
label: item.name,
}));
},
required: true,
},
{
name: "headers",
label: "HTTP Headers",
kind: "multi",
size: 12,
helperText: "Useful for including authentication headers",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
required: true,
size: 12,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
required: true,
size: 12,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};

View file

@ -0,0 +1,86 @@
import { ServiceConfig } from "@/app/_lib/service";
export const whatsappConfig: ServiceConfig = {
entity: "whatsapp",
table: "WhatsappBot",
displayName: "WhatsApp Connection",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
{
name: "token",
label: "Token",
hidden: true,
required: true,
autogenerated: "token",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
},
{
name: "token",
label: "Token",
copyable: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "phoneNumber",
headerName: "Phone Number",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};

View file

@ -4,6 +4,7 @@ import {
createAction,
updateAction,
deleteAction,
selectAllAction,
} from "@/app/_actions/service";
type GenerateCreateActionArgs = {
@ -18,6 +19,8 @@ export function generateCreateAction({
fields,
}: GenerateCreateActionArgs) {
return async (currentState: any, formData: FormData) => {
console.log({ entity, table, fields });
console.log({ currentState, formData });
return createAction({
entity,
table,
@ -63,3 +66,9 @@ export function generateDeleteAction({
return deleteAction({ entity, table, id });
};
}
export function generateSelectAllAction(table: keyof Database) {
return async () => {
return selectAllAction(table);
};
}

View file

@ -115,6 +115,11 @@ export interface Database {
id: GeneratedAlways<string>;
name: string;
description: string;
backendType: string;
backendId: string;
endpointUrl: string;
httpMethod: "post" | "put";
headers: Record<string, any>;
createdBy: string;
createdAt: Date;
updatedAt: Date;

View file

@ -1,138 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { Service, ServiceConfig } from "./service";
import { makeWorkerUtils, WorkerUtils } from "graphile-worker";
import { Service } from "./service";
import { db } from "./database";
export const facebookConfig: ServiceConfig = {
entity: "facebook",
table: "FacebookBot",
displayName: "Facebook Connection",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{ name: "appId", label: "App ID", required: true },
{ name: "appSecret", label: "App Secret", required: true },
{ name: "pageId", label: "Page ID", required: true },
{
name: "pageAccessToken",
label: "Page Access Token",
required: true,
},
{
name: "token",
label: "Token",
hidden: true,
required: true,
autogenerated: "token",
},
{
name: "verifyToken",
label: "Verify Token",
hidden: true,
required: true,
autogenerated: "token",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "token",
label: "Token",
disabled: true,
refreshable: true,
},
{
name: "verifyToken",
label: "Verify Token",
disabled: true,
refreshable: true,
},
{ name: "appId", label: "App ID", required: true },
{ name: "appSecret", label: "App Secret", required: true },
{ name: "pageId", label: "Page ID", required: true },
{
name: "pageAccessToken",
label: "Page Access Token",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
required: true,
size: 12,
},
{
name: "token",
label: "Token",
copyable: true,
},
{
name: "verifyToken",
label: "Verify Token",
copyable: true,
},
let workerUtils: WorkerUtils;
{ name: "appId", label: "App ID", required: true },
{ name: "appSecret", label: "App Secret", required: true },
{
name: "pageId",
label: "Page ID",
required: true,
copyable: true,
},
{
name: "pageAccessToken",
label: "Page Access Token",
required: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};
const getWorkerUtils = async () => {
if (!workerUtils) {
workerUtils = await makeWorkerUtils({
connectionString: process.env.DATABASE_URL,
});
}
const getAllBots = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const getOneBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
return workerUtils;
};
const sendMessage = async (req: NextRequest) => {
@ -147,80 +27,75 @@ const receiveMessages = async (req: NextRequest) => {
return NextResponse.json({ response: "ok" });
};
const registerBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const resetBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const requestCode = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const unverifyBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const refreshBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const createBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const deleteBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const handleWebhook = async (req: NextRequest) => {
console.log({ req });
const { searchParams } = req.nextUrl;
const token = searchParams.get("hub.verify_token");
const submittedToken = searchParams.get("hub.verify_token");
if (token !== process.env.FB_VERIFY_TOKEN) {
// return NextResponse.error("Invalid token", { status: 403 });
if (submittedToken) {
console.log({ submittedToken });
const row = await db
.selectFrom("FacebookBot")
.selectAll()
.where("verifyToken", "=", submittedToken)
.executeTakeFirst();
console.log({ row });
if (!row) {
return NextResponse.error();
}
if (searchParams.get("hub.mode") === "subscribe") {
const challenge = searchParams.get("hub.challenge");
console.log(submittedToken);
console.log(challenge);
return NextResponse.json(challenge) as any;
}
}
if (searchParams.get("hub.mode") === "subscribe") {
const challenge = searchParams.get("hub.challenge");
console.log(token);
console.log(challenge);
const message = await req.json();
console.log({ message });
const entry = message.entry[0];
console.log({ entry });
const messaging = entry?.messaging[0];
const pageId = messaging?.recipient?.id;
console.log({ pageId });
const row = await db
.selectFrom("FacebookBot")
.selectAll()
.where("pageId", "=", pageId)
.executeTakeFirst();
return new Response(challenge, { status: 200 }) as NextResponse;
}
console.log({ row });
const endpoint = `https://graph.facebook.com/v19.0/${pageId}/messages`;
const inMessage = messaging?.message?.text;
const outgoingMessage = {
recipient: { id: messaging?.sender?.id },
message: { text: `"${inMessage}", right back at you!` },
messaging_type: "RESPONSE",
access_token: row?.pageAccessToken,
};
console.log({ outgoingMessage });
const response = await fetch(endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(outgoingMessage),
});
console.log({ response });
console.log(message);
const wu = await getWorkerUtils();
await wu.addJob("receive_facebook_message", message);
return NextResponse.json({ response: "ok" });
};
export const Facebook: Service = {
getAllBots,
getOneBot,
sendMessage,
receiveMessages,
registerBot,
resetBot,
requestCode,
unverifyBot,
refreshBot,
createBot,
deleteBot,
handleWebhook,
};

View file

@ -1,50 +1,17 @@
import { NextRequest, NextResponse } from "next/server";
import { Service } from "./service";
import { Facebook } from "./facebook";
import { getService } from "./utils";
const services: Record<string, Service> = {
facebook: Facebook,
none: NextResponse.error() as any,
};
const getService = (req: NextRequest): Service => {
const service = req.nextUrl.searchParams.get("service") ?? "none";
return services[service];
};
export const getAllBots = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.getAllBots(req);
const notFound = () => new NextResponse(null, { status: 404 });
export const getOneBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.getOneBot(req);
notFound();
export const sendMessage = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.sendMessage(req);
getService(req)?.sendMessage(req) ?? notFound();
export const receiveMessages = async (
req: NextRequest,
): Promise<NextResponse> => getService(req)?.receiveMessages(req);
export const registerBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.registerBot(req);
export const resetBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.resetBot(req);
export const requestCode = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.requestCode(req);
export const unverifyBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.unverifyBot(req);
export const refreshBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.refreshBot(req);
export const createBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.createBot(req);
export const deleteBot = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.deleteBot(req);
): Promise<NextResponse> => getService(req)?.receiveMessages(req) ?? notFound();
export const handleWebhook = async (req: NextRequest): Promise<NextResponse> =>
getService(req)?.handleWebhook(req);
getService(req)?.handleWebhook(req) ?? notFound();

View file

@ -13,9 +13,16 @@ const entities = [
export type Entity = (typeof entities)[number];
export type SelectOption = {
value: string;
label: string;
};
export type FieldDescription = {
name: string;
label: string;
kind?: "text" | "phone" | "select" | "multi";
getOptions?: (formState: any) => Promise<SelectOption[]>;
autogenerated?: "token";
hidden?: boolean;
type?: string;
@ -39,17 +46,18 @@ export type ServiceConfig = {
listColumns: GridColDef[];
};
export type Service = {
getAllBots: (req: NextRequest) => Promise<NextResponse>;
getOneBot: (req: NextRequest) => Promise<NextResponse>;
sendMessage: (req: NextRequest) => Promise<NextResponse>;
receiveMessages: (req: NextRequest) => Promise<NextResponse>;
registerBot: (req: NextRequest) => Promise<NextResponse>;
resetBot: (req: NextRequest) => Promise<NextResponse>;
requestCode: (req: NextRequest) => Promise<NextResponse>;
unverifyBot: (req: NextRequest) => Promise<NextResponse>;
refreshBot: (req: NextRequest) => Promise<NextResponse>;
createBot: (req: NextRequest) => Promise<NextResponse>;
deleteBot: (req: NextRequest) => Promise<NextResponse>;
handleWebhook: (req: NextRequest) => Promise<NextResponse>;
};
export class Service {
sendMessage: (req: NextRequest) => Promise<NextResponse> = async (req) => {
return NextResponse.json({ ok: "nice" });
};
receiveMessages: (req: NextRequest) => Promise<NextResponse> = async (
req,
) => {
return NextResponse.json({ ok: "nice" });
};
handleWebhook: (req: NextRequest) => Promise<NextResponse> = async (req) => {
return NextResponse.json({ ok: "nice" });
};
}

View file

@ -1,102 +1,5 @@
import { NextRequest, NextResponse } from "next/server";
import { Service, ServiceConfig } from "./service";
export const signalConfig: ServiceConfig = {
entity: "signal",
table: "SignalBot",
displayName: "Signal Connection",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "phoneNumber",
label: "phoneNumber",
required: true,
},
{
name: "token",
label: "Token",
hidden: true,
required: true,
autogenerated: "token",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "phoneNumber",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "phoneNumber",
},
{
name: "token",
label: "Token",
copyable: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "phoneNumber",
headerName: "Phone Number",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};
const getAllBots = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const getOneBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
import { Service } from "./service";
const sendMessage = async (req: NextRequest) => {
console.log({ req });
@ -110,48 +13,6 @@ const receiveMessages = async (req: NextRequest) => {
return NextResponse.json({ response: "ok" });
};
const registerBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const resetBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const requestCode = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const unverifyBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const refreshBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const createBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const deleteBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const handleWebhook = async (req: NextRequest) => {
console.log({ req });
@ -159,16 +20,7 @@ const handleWebhook = async (req: NextRequest) => {
};
export const Signal: Service = {
getAllBots,
getOneBot,
sendMessage,
receiveMessages,
registerBot,
resetBot,
requestCode,
unverifyBot,
refreshBot,
createBot,
deleteBot,
handleWebhook,
};

View file

@ -0,0 +1,13 @@
import { NextRequest } from "next/server";
import { Service } from "./service";
import { Facebook } from "./facebook";
const services: Record<string, Service> = {
facebook: Facebook,
};
export const getService = (req: NextRequest): Service => {
const service = req.nextUrl.pathname.split("/")?.[2] ?? "none";
return services[service];
};

View file

@ -1,93 +1,5 @@
import { NextRequest, NextResponse } from "next/server";
import { Service, ServiceConfig } from "./service";
export const voiceConfig: ServiceConfig = {
entity: "voice",
table: "VoiceLine",
displayName: "Voice Line",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "phoneNumber",
label: "phoneNumber",
required: true,
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
required: true,
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
required: true,
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "phoneNumber",
headerName: "Phone Number",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};
const getAllBots = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const getOneBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
import { Service } from "./service";
const sendMessage = async (req: NextRequest) => {
console.log({ req });
@ -101,48 +13,6 @@ const receiveMessages = async (req: NextRequest) => {
return NextResponse.json({ response: "ok" });
};
const registerBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const resetBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const requestCode = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const unverifyBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const refreshBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const createBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const deleteBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const handleWebhook = async (req: NextRequest) => {
console.log({ req });
@ -150,16 +20,7 @@ const handleWebhook = async (req: NextRequest) => {
};
export const Voice: Service = {
getAllBots,
getOneBot,
sendMessage,
receiveMessages,
registerBot,
resetBot,
requestCode,
unverifyBot,
refreshBot,
createBot,
deleteBot,
handleWebhook,
};

View file

@ -1,102 +1,5 @@
import { NextRequest, NextResponse } from "next/server";
import { Service, ServiceConfig } from "./service";
export const whatsappConfig: ServiceConfig = {
entity: "whatsapp",
table: "WhatsappBot",
displayName: "WhatsApp Connection",
createFields: [
{
name: "name",
label: "Name",
required: true,
size: 12,
},
{
name: "description",
label: "Description",
size: 12,
lines: 3,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
{
name: "token",
label: "Token",
hidden: true,
required: true,
autogenerated: "token",
},
],
updateFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
required: true,
},
],
displayFields: [
{ name: "name", label: "Name", required: true, size: 12 },
{
name: "description",
label: "Description",
size: 12,
},
{
name: "phoneNumber",
label: "Phone Number",
},
{
name: "token",
label: "Token",
copyable: true,
},
],
listColumns: [
{
field: "name",
headerName: "Name",
flex: 1,
},
{
field: "phoneNumber",
headerName: "Phone Number",
flex: 1,
},
{
field: "description",
headerName: "Description",
flex: 2,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
],
};
const getAllBots = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const getOneBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
import { Service } from "./service";
const sendMessage = async (req: NextRequest) => {
console.log({ req });
@ -110,48 +13,6 @@ const receiveMessages = async (req: NextRequest) => {
return NextResponse.json({ response: "ok" });
};
const registerBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const resetBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const requestCode = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const unverifyBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const refreshBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const createBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const deleteBot = async (req: NextRequest) => {
console.log({ req });
return NextResponse.json({ response: "ok" });
};
const handleWebhook = async (req: NextRequest) => {
console.log({ req });
@ -159,16 +20,7 @@ const handleWebhook = async (req: NextRequest) => {
};
export const Whatsapp: Service = {
getAllBots,
getOneBot,
sendMessage,
receiveMessages,
registerBot,
resetBot,
requestCode,
unverifyBot,
refreshBot,
createBot,
deleteBot,
handleWebhook,
};

View file

@ -1 +0,0 @@
export { registerBot as POST } from "@/app/_lib/routing";

View file

@ -1 +0,0 @@
export { requestCode as POST } from "@/app/_lib/routing";

View file

@ -1 +0,0 @@
export { resetBot as POST } from "@/app/_lib/routing";

View file

@ -1 +0,0 @@
export { getAllBots as GET } from "@/app/_lib/routing";

View file

@ -1,8 +1,6 @@
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { handleWebhook } from "@/app/_lib/routing";
const handleRequest = async (req: NextRequest, res: NextResponse) => {
return NextResponse.json({ message: "ok" });
};
const handleRequest = async (req: NextRequest) => handleWebhook(req);
export { handleRequest as GET, handleRequest as POST };

View file

@ -26,6 +26,7 @@
"@mui/x-license": "^7.2.0",
"date-fns": "^3.6.0",
"dotenv": "^16.4.5",
"graphile-worker": "^0.16.6",
"kysely": "^0.26.1",
"material-ui-popup-state": "^5.1.0",
"mui-chips-input": "^2.1.4",