Skip to content

Commit

Permalink
Working on UI changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
abhik-wil committed Jan 8, 2025
1 parent f4ac96a commit e7bb242
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 131 deletions.
61 changes: 38 additions & 23 deletions deeplink-generator/README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# Deep Link v2
This repo holds the code for Deep Link v2 App. It is a utility provided to generate usecases from predefined templates. There are 3 personas concerned in this app. These personas are:
1. Admin
2. User
3. Consumer

## Getting Started
Out of these, currently, the User flow has been enabled. Remaining flows are under development and will be introduced in future releases.

First, run the development server:
## Admin
The admin is responsible to **creating** templates. These templates inherit schema from the Base Beckn template. The admin can then add fields to the template. There are 3 types of fields:
1. Pre-filled - These fields are defined and their values are provided by the admin. These fields are not editable by the user. So any usecase created with these templates will have the same values for these fields.
2. User-filled - The admin can mark a field as "user-filled". This field will be editable by the user. The user can provide their own values for these fields during usecase generation.
3. PG - These fields are filled during consumption phase. The usecase created with the template will have these fields marked and the resolver server will communicate with the agent to fill these fields.

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
## User
The user is responsible to **creating** usecases. The user can select a template and then add fields to the template. The user can then generate the usecase. The usecase will be generated in the form of a JSON file. The user can then use this JSON file to create a usecase on the Beckn network.

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
The usecases may be kept private or public (saveed to GitHub). Additionally, when the usecase is either published privately (submitted) or published, the usecase QR is saved on Github. This QR contains the ID of the usecase. The resolver server can then use this ID to fetch the usecase.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
## Consumer
The consumer is responsible to **consuming** usecases. The consumer can scan the QR of the usecase and the resolver server will fetch the usecase. The resolver server will then communicate with the "consuming" agent to fill the fields marked as PG. The resolver server will then return the usecase to the consumer. The consumer can then use this usecase to create a usecase on the Beckn network.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
Currently, hitting `/api/resolver/{usecase_id}` will resolve the usecase. *Note*: While this returns the usecase, it does not resolve the usecase. The usecase is resolved when the resolver server communicates with the agent and all the post-generation fields are filled. **Post Generation fields are denoted with `{{<value>}}`.

## Learn More
## Developer Guide

To learn more about Next.js, take a look at the following resources:
This section is meant for developers who want to contribute to the project. The project is built using NextJS and PostgreSQL. Prisma ORM has been used.

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
### Prerequisites
Knowledge of NextJS 15, TypeScript, PostgreSQL, Docker, Docker Compose, Prisma ORM, and Beckn Protocol is required.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
You need to have the following before you can start developing:
1. NodeJS (^22.0)
2. Docker & Docker Compose

## Deploy on Vercel
### Steps to start the project
1. Clone the repo
2. RUN `cd deeplink-generator`
3. Run `npm install`
4. Copy the `example.env` file to `.env` and update the values as needed.
5. Copy the `docker-compose.local.yml` to `docker-compose.yml`.
6. RUN `docker compose up ondc_deep_link_db -d`. This will start the database in a docker container.
7. RUN `npx prisma migrate dev` followed by `npx prisma seed` to seed the database.
8. RUN `npm run dev` to start the project.

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
### Seeding the database
The database comes pre-seeded with the templates defined inside the `seeding` directory once step 7 in the previous sub-section is completed. The seeding script automatically picks up on the usecase category and sub-category as defined in the templates and seeds them accordingly.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
## Contributors:
1. [Abhik Banerjee](https://github.com/abhik-wil)
2. [Sonali Shakya](https://github.com/sonalishakya)
17 changes: 3 additions & 14 deletions deeplink-generator/docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ services:
- "8080:3000"
environment:
- DATABASE_URL=${DATABASE_URL}
- ENV=${ENV}
depends_on:
- ondc_deep_link_db

Expand All @@ -23,17 +22,7 @@ services:
ports:
- "5432:5432"
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASS}
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}

ondc_deep_link_nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- ondc_deep_link_app
9 changes: 9 additions & 0 deletions deeplink-generator/example.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
POSTGRES_USER=
POSTGRES_PASS=
POSTGRES_NAME=
DATABASE_URL=

ACCESS_TOKEN_REPO=
OWNER_NAME_REPO=
STORAGE_REPO_NAME=

44 changes: 0 additions & 44 deletions deeplink-generator/nginx/nginx.conf

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
inputTypeMapper,
NamedEnum,
} from "@/app/utils";
import { createDeepLink, getTemplateById } from "@/app/actions";
import { createUsecase, getTemplateById } from "@/app/actions";
import {
CustomContainedButtom,
CustomHeading,
Expand All @@ -33,17 +33,33 @@ const GenerateDeepLinkPage = async ({
const templateId = (await params).templateId;
const template = await getTemplateById(templateId);
const templateValue = flattenTemplate(template!.value);
console.log("TEMPLATE VALUE", templateValue);

const handleSubmit = async (form: FormData) => {
"use server";
if (!form) {
throw new Error("Form data is required");
const value = formDataToFormItemArray(form);
let valid = true;
value.forEach((item) => {
if (item.value.startsWith("{{") || item.value.endsWith("}}")) {
valid = false;
throw alert(`Invalid Input`);
}
});

if (valid) {
const deepLink = await createUsecase({
templateId,
value: value.map(({ name, value }) => {
try {
JSON.parse(value);
return { name, value: `{{${name}}}` };
} catch {
return { name, value };
}
}),
});

redirect(`/deep-link/usecases/publish/${deepLink.id}`);
}
console.log("CREATING DEEP LINK");
const value = formDataToFormItemArray(form)
const deepLink = await createDeepLink({templateId, value});
console.log("Redirecting");
redirect(`/deep-link/usecases/publish/${deepLink.id}`);
};
return (
<>
Expand Down Expand Up @@ -158,6 +174,7 @@ const GenerateDeepLinkPage = async ({
}
fullWidth
name={key}
required
>
{(templateValue[key] as FillerTypeObject).enum?.map(
(value, index) => (
Expand Down Expand Up @@ -189,6 +206,7 @@ const GenerateDeepLinkPage = async ({
sx={{ ml: 1 }}
name={key}
fullWidth
required
/>
)}
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const PublishDeepLinkPage = async ({
>
<FieldName fieldName="Deeplink Name" />
<Typography variant="h5">&nbsp; &nbsp;</Typography>
<TextField sx={{ ml: 1 }} name="name" fullWidth />
<TextField sx={{ ml: 1 }} name="name" fullWidth required/>
</Stack>

<Stack
Expand All @@ -90,7 +90,7 @@ const PublishDeepLinkPage = async ({
>
<FieldName fieldName="Description" />
<Typography variant="h5">&nbsp; &nbsp;</Typography>
<TextField sx={{ ml: 1 }} name="description" fullWidth />
<TextField sx={{ ml: 1 }} name="description" fullWidth required/>
</Stack>

<Divider />
Expand All @@ -106,6 +106,7 @@ const PublishDeepLinkPage = async ({
name="submissionOption"
defaultValue={UsecaseStage.PUBLISHED}
fullWidth
required
>
<MenuItem value={UsecaseStage.SUBMITTED}>
Save Private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,23 @@ import { UsecaseStage } from "@prisma/client";
import { db } from "../../../db";
import { FormItem, inflateDeepLink } from "../utils";

export type CreateDeepLinkType = {
export type CreateUsecaseType = {
templateId: string;
value: FormItem[];
};

export async function createDeepLink({
export async function createUsecase({
templateId,
value,
}: CreateDeepLinkType) {
console.log("Generating Deep Link...", templateId, value);
}: CreateUsecaseType) {
const inflatedValue = inflateDeepLink(value);
console.log("VALUE INFLATED", inflatedValue);
const deepLink = await db.usecase.create({
data: {
templateId,
value: inflatedValue,
usecaseStage: UsecaseStage.DRAFT,
},
});
console.log("USE CASE CREATED", deepLink);

return deepLink;
}
2 changes: 1 addition & 1 deletion deeplink-generator/src/app/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from "./create-deep-link";
export * from "./create-usecase";
export * from "./create-template";
export * from "./publish-template";
export * from "./get-usecase-categories";
Expand Down
22 changes: 17 additions & 5 deletions deeplink-generator/src/app/actions/publish-usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type PublishUsecaseFormType = {
const FOLDER_PATH = "usecases";

export async function publishUsecase({ usecase, form }: PublishUsecaseType) {
const updatedUsecase = await db.usecase.update({
const { value, ...updatedUsecase } = await db.usecase.update({
where: {
id: usecase.id,
},
Expand All @@ -30,15 +30,20 @@ export async function publishUsecase({ usecase, form }: PublishUsecaseType) {
description: form.description,
},
});
console.log("ENVs", process.env.OWNER_NAME_REPO, process.env.STORAGE_REPO_NAME, process.env.ACCESS_TOKEN_REPO);
const octokit = new Octokit({
auth: process.env.ACCESS_TOKEN_REPO,
});

if (form.submissionOption === UsecaseStage.PUBLISHED) {
const fileName = `${updatedUsecase.id}.json`;
const filePath = `${FOLDER_PATH}/json/${fileName}`;
const content = Buffer.from(
const content = Buffer.from(JSON.stringify(value, null, 2)).toString(
"base64"
);

const metaFileName = `${updatedUsecase.id}-meta.json`;
const metaFilePath = `${FOLDER_PATH}/meta/${metaFileName}`;
const metaContent = Buffer.from(
JSON.stringify(updatedUsecase, null, 2)
).toString("base64");

Expand All @@ -61,21 +66,28 @@ export async function publishUsecase({ usecase, form }: PublishUsecaseType) {
}
}

// Create the new JSON file
await octokit.repos.createOrUpdateFileContents({
owner: process.env.OWNER_NAME_REPO || "",
repo: process.env.STORAGE_REPO_NAME || "",
path: filePath,
message: `Add user submission ${updatedUsecase.id}`,
content,
});

await octokit.repos.createOrUpdateFileContents({
owner: process.env.OWNER_NAME_REPO || "",
repo: process.env.STORAGE_REPO_NAME || "",
path: metaFilePath,
message: `Add user submission ${updatedUsecase.id}-meta`,
content: metaContent,
});
}

const fileName = `${updatedUsecase.id}.png`;
const filePath = `${FOLDER_PATH}/qr/${fileName}`;

const qrCodeBase64 = await QRCode.toDataURL(
JSON.stringify(updatedUsecase.value, null, 2)
`beckn://github.ondc.ret10/${updatedUsecase.id}`
);

// Convert base64 to buffer (remove data:image/png;base64, prefix)
Expand Down
Loading

0 comments on commit e7bb242

Please sign in to comment.