Skip to content

Commit 838f449

Browse files
committed
feat: ✨ Add preview route
1 parent 716f84c commit 838f449

File tree

9 files changed

+117
-43
lines changed

9 files changed

+117
-43
lines changed

apps/api/.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@ yarn-error.log*
3939
**/*.tgz
4040
**/*.log
4141
package-lock.json
42-
**/*.bun
42+
**/*.bun
43+
44+
.cache/

apps/api/bun.lockb

1022 Bytes
Binary file not shown.

apps/api/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
"description": "Invoicelink.io API Endpoints",
55
"scripts": {
66
"dev": "bun --watch src/index.ts",
7-
"build": "bun build src/index.ts --outdir=dist",
7+
"build": "bun build src/index.ts --outdir=.dist",
88
"start": "NODE_ENV=production bun src/index.ts",
99
"test": "bun test",
1010
"postinstall": "bunx puppeteer browsers install chrome"
1111
},
1212
"dependencies": {
1313
"@elysiajs/swagger": "^1.1.0",
14+
"cloudinary": "^2.4.0",
1415
"elysia": "latest",
1516
"puppeteer": "^23.0.2"
1617
},

apps/api/src/index.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
import { Elysia } from "elysia";
22
import { swagger } from '@elysiajs/swagger'
33
import invoice from "./invoice";
4+
import preview from "./preview";
5+
const { version } = require("../package.json");
46

5-
6-
const app = new Elysia().use(invoice).use(swagger({
7+
const app = new Elysia({
8+
}).use(invoice).use(preview).use(swagger({
79
path: "/",
8-
version: "1.1.0",
9-
})).listen(3000);
10+
documentation: {
11+
info: {
12+
title: 'Invoicelink.io',
13+
version,
14+
description: 'Internal API Documentation',
15+
},
16+
}
17+
}));
18+
19+
app.listen(3000);
1020

1121
console.log(
12-
`🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port}`
22+
`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
1323
);
24+
25+

apps/api/src/invoice.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import { Elysia } from 'elysia'
1+
import { Elysia, t } from 'elysia'
22
import puppeteer from 'puppeteer';
33

44
const plugin = new Elysia()
55
.get('/invoice', async ({
66
query
7+
}: {
8+
query: {
9+
id: string;
10+
type: string;
11+
download?: string;
12+
}
713
}) => {
8-
console.log(query)
914
const { id, type, download } = query
1015

1116
let browser = await puppeteer.launch({ headless: true });
@@ -19,12 +24,41 @@ const plugin = new Elysia()
1924

2025
await browser.close();
2126

22-
return new Response(pdf, {
27+
return new Response(pdf as unknown as File, {
2328
headers: {
2429
'Content-Type': 'application/pdf',
2530
'Content-Disposition': download ? `attachment; filename="invoice.pdf"` : `inline`
26-
}
31+
},
32+
status: 200
2733
});
28-
});
34+
}, {
35+
query: t.Object({
36+
id: t.String({
37+
description: 'An invoice or quicklink id',
38+
error: 'Please provide an id'
39+
}),
40+
type: t.String({
41+
description: 'The type of document to generate',
42+
enum: ['invoice', 'quicklink'],
43+
default: 'invoice',
44+
error: 'Please provide a type'
45+
}),
46+
download: t.Optional(t.Boolean({
47+
description: 'Whether to download the file or display it in the browser',
48+
default: false,
49+
error: 'Please provide a boolean download option'
50+
}))
51+
}),
52+
response: t.Any({
53+
description: 'The generated invoice or quicklink',
54+
type: 'application/pdf',
55+
example: 'invoice.pdf',
56+
error: 'An error occurred generating the PDF'
57+
}),
58+
detail: {
59+
summary: 'Generate PDF Invoice',
60+
description: 'Create a PDF for an invoice or quicklink',
61+
}
62+
});
2963

3064
export default plugin

apps/api/src/preview.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Elysia, t } from 'elysia'
2+
import puppeteer from 'puppeteer';
3+
4+
const plugin = new Elysia()
5+
.get('/preview', async ({
6+
query
7+
}: {
8+
query: {
9+
styleId: string;
10+
}
11+
}) => {
12+
console.log(query)
13+
const { styleId } = query
14+
15+
let browser = await puppeteer.launch({ headless: true });
16+
const page = await browser.newPage();
17+
18+
await page.goto(`https://app.invoicelink.io/invoice?styleId=${styleId}`,{ waitUntil: 'domcontentloaded' });
19+
const img = await page.screenshot({
20+
fullPage: true,
21+
optimizeForSpeed: true,
22+
quality: 70,
23+
omitBackground: true,
24+
type: 'webp'
25+
});
26+
27+
await browser.close();
28+
29+
return new Response(img, {
30+
headers: {
31+
'Content-Type': 'image/webp'
32+
},
33+
status: 200
34+
});
35+
}, {
36+
query: t.Object({
37+
styleId: t.String({
38+
description: 'An invoice template style id',
39+
error: 'Please provide an invoice template style id'
40+
}),
41+
}),
42+
response: t.Any({
43+
description: 'Screenshot of the template styles',
44+
type: 'image/webp',
45+
error: 'An error occurred generating the preview'
46+
}),
47+
detail: {
48+
summary: 'Generate Style Preview',
49+
description: 'Create a preview image for invoice template styles',
50+
}
51+
});
52+
53+
export default plugin

apps/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"private": true,
77
"homepage": "https://app.invoicelink.io",
88
"scripts": {
9-
"dev": "vite dev --open --port 5173",
9+
"dev": "vite dev --port 5173",
1010
"build": "vite build",
1111
"preview": "vite preview",
1212
"test": "npm run test:integration && npm run test:unit",

apps/app/src/routes/(app)/api/image-upload/+server.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

apps/app/src/routes/pay/+page.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
<div data-theme="light" class="flex h-svh w-full flex-col pb-20">
4949
{#if data.pay}
5050
<div
51-
class="bg-pattern relative flex h-[25vh] w-full flex-col items-center justify-center bg-base-200 text-center"
51+
class="bg-pattern bg-base-200 relative flex h-[25vh] w-full flex-col items-center justify-center text-center"
5252
>
5353
<div
54-
class="absolute bottom-0 z-10 -mb-[10vh] flex h-auto w-[90vw] flex-col items-center justify-center gap-4 rounded-xl bg-base-100 p-10 shadow-lg sm:mx-auto sm:w-full sm:max-w-xl"
54+
class="bg-base-100 absolute bottom-0 z-10 -mb-[10vh] flex h-auto w-[90vw] flex-col items-center justify-center gap-4 rounded-xl p-10 shadow-lg sm:mx-auto sm:w-full sm:max-w-xl"
5555
>
5656
<div class="flex flex-col items-center">
5757
<div class="-mt-4 mb-4">

0 commit comments

Comments
 (0)