Skip to content

Commit

Permalink
Feat/pdf meta (auvoid#5)
Browse files Browse the repository at this point in the history
* feat: save meta data with pdf

* feat: add metadata validation page

* fix: add dash login check
  • Loading branch information
sosweetham authored Nov 3, 2024
1 parent bafa4cc commit 4708a12
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 18 deletions.
2 changes: 2 additions & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
"dependencies": {
"@sveltejs/adapter-node": "^5.2.8",
"axios": "^1.7.7",
"jspdf": "^2.5.2",
"moment": "^2.30.1",
"pdfjs-dist": "^4.8.69",
"svelte-qrcode-action": "^1.0.2"
}
}
4 changes: 3 additions & 1 deletion apps/client/src/lib/components/fragments/CvPreview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
export let role: string;
export let cvId: string;
export let toPdf: HTMLDivElement
$: cvUrl = new URL(`/verify/cvId`, PUBLIC_CLIENT_URI).toString();
</script>

<div class="flex flex-col items-center self-center">
<div class="aspect-[1/1.414] min-w-[595px] flex">
<div class="aspect-[1/1.414] min-w-[595px] flex" bind:this={toPdf}>
<div class="w-[30%] h-full bg-cyan-900 py-10 px-4 flex flex-col justify-between items-center">
<div>
<div>
Expand Down
16 changes: 16 additions & 0 deletions apps/client/src/routes/(private)/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
<script lang="ts">
import { apiClient } from '$lib/axios/axios';
import Header from '$lib/components/fragments/Header.svelte';
import Sidebar from '$lib/components/fragments/Sidebar.svelte';
import { onMount } from 'svelte';
import { addToast } from '../store';
import { goto } from '$app/navigation';
onMount(async () => {
const { data } = (await apiClient.get('/users').catch(() => {
addToast({ type: 'error', message: 'Login Error' });
goto('/login');
return { data: null };
})) as { data: { id: string } };
if (!data.id) {
goto('/login');
}
console.log(data);
});
</script>

<div class="w-full">
Expand Down
55 changes: 43 additions & 12 deletions apps/client/src/routes/(private)/dashboard/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { apiClient } from '$lib/axios/axios';
import CvPreview from '$lib/components/fragments/CvPreview.svelte';
import DocPreviewBar from '$lib/components/fragments/DocPreviewBar.svelte';
import Badge from '$lib/components/ui/Badge.svelte';
import Button from '$lib/components/ui/Button.svelte';
import {
Card,
Expand All @@ -17,22 +17,22 @@
TableHead,
TableHeadCell
} from 'flowbite-svelte';
import {
CheckCircleSolid,
DotsHorizontalOutline,
ExclamationCircleSolid
} from 'flowbite-svelte-icons';
import { DotsHorizontalOutline, ExclamationCircleSolid } from 'flowbite-svelte-icons';
import moment from 'moment';
import { onMount } from 'svelte';
import { onMount, tick } from 'svelte';
import { jsPDF } from 'jspdf';
import { PUBLIC_BASE_URI } from '$env/static/public';
let selectedDoc: boolean;
let docName: string;
let signingParties: string[];
let isSigned: boolean;
let cvs: Record<string, any>[];
let selectedCv: Record<string, any>;
let handlePdfSave: (cv: Record<string, string>) => void | Promise<void>;
let handleDownloadClick: (cv: Record<string, string>) => void | Promise<void>;
let makePdf: HTMLDivElement;
async function handleDelete(id: string) {
await apiClient.delete(`/cv/${id}`);
await fetchCvs();
Expand All @@ -43,8 +43,36 @@
cvs = data;
}
onMount(() => {
onMount(async () => {
fetchCvs();
const html2pdf = (await import('html2pdf.js')).default;
let html2PdfWorker = html2pdf();
handlePdfSave = async (cv) => {
let opt = {
margin: [0, 0, 0, 0],
filename: 'YourVCV.pdf',
image: { type: 'png' },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'p', putOnlyUsedFonts: true }
};
const doc = await html2PdfWorker.from(makePdf).set(opt).toPdf().get('pdf');
console.log(cv.id);
await doc.addMetadata(cv.id, PUBLIC_BASE_URI);
console.log(doc);
doc.save('VCV.pdf');
};
handleDownloadClick = async (cv: Record<string, string>) => {
selectedCv = cv;
// wait for dom data
await tick();
handlePdfSave(cv);
};
const urlParams = new URLSearchParams($page.url.search);
});
</script>

Expand Down Expand Up @@ -76,7 +104,9 @@
>Edit VCV</DropdownItem
>
<DropdownItem on:click={() => handleDelete(cv.id)}>Delete VCV</DropdownItem>
<DropdownItem>Download VCV</DropdownItem>
<DropdownItem on:click={() => handleDownloadClick(cv)}
>Download VCV</DropdownItem
>
</Dropdown>
</button>
</div>
Expand Down Expand Up @@ -109,6 +139,7 @@
phoneNum={selectedCv.contacts.phone}
email={selectedCv.contacts.email}
cvId={selectedCv.id}
bind:toPdf={makePdf}
></CvPreview>
{:else if !cvs}
<p class="w-full py-8 text-center">You don't have any VCV to view yet :(</p>
Expand Down
5 changes: 2 additions & 3 deletions apps/client/src/routes/(private)/new-vcv/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import Step2 from './steps/step2.svelte';
import Step3 from './steps/step3.svelte';
import Step4 from './steps/step4.svelte';
import Step5 from './steps/step5.svelte';
import Step5 from './steps/step5.svelte';
import Button from '$lib/components/ui/Button.svelte';
import { goto } from '$app/navigation';
import { apiClient } from '$lib/axios/axios';
Expand Down Expand Up @@ -109,7 +109,6 @@
credentials = data.credentials;
experiences = data.experiences;
}
});
</script>

Expand All @@ -124,7 +123,7 @@
{:else if step === 2}
<Step3 bind:selectedCredentials={credentials}></Step3>
{:else if step === 3}
<Step4></Step4>
<Step4 {cvId}></Step4>
{:else if step === 4}
<Step5 onSavePdfClick={handlePdfSave}></Step5>
{/if}
Expand Down
79 changes: 79 additions & 0 deletions apps/client/src/routes/(public)/verify/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script lang="ts">
import { goto } from '$app/navigation';
import Button from '$lib/components/ui/Button.svelte';
import { Dropzone, Label } from 'flowbite-svelte';
import { UploadOutline } from 'flowbite-svelte-icons';
import { onMount } from 'svelte';
export let isPdfUploading: boolean;
export let fileName: undefined | string;
export let pdfFile: FileList | undefined;
let uploadHandler: () => Promise<void>;
const dropHandle = (event: DragEvent) => {
event.preventDefault();
if (event.dataTransfer?.items) {
fileName = [...event.dataTransfer.items][0].getAsFile()?.name;
}
if (!pdfFile || !pdfFile[0]) return;
uploadHandler();
};
const handleChange = (event: Event) => {
const useEvent = event as DragEvent;
if (useEvent.dataTransfer && useEvent.dataTransfer.items) {
fileName = [...useEvent.dataTransfer.items][0].getAsFile()?.name;
}
if (!pdfFile || !pdfFile[0]) return;
uploadHandler();
};
onMount(async () => {
const pdfjs = await import('pdfjs-dist');
pdfjs.GlobalWorkerOptions.workerSrc = '/scripts/pdf.worker.min.mjs';
uploadHandler = async () => {
if (!pdfFile || !pdfFile[0]) return;
const pdfDoc = await pdfjs.getDocument(await pdfFile[0].arrayBuffer()).promise;
const metadata = (await pdfDoc.getMetadata()).metadata.getAll() as {
'jspdf:metadata': string;
};
if (metadata['jspdf:metadata']) {
goto(`/verify/${metadata['jspdf:metadata']}`);
}
};
});
</script>

<div class="w-full">
<Label class="text-font-bold text-md mb-1">Upload Document to be signed</Label>
{#if !isPdfUploading}
<Dropzone
on:drop={dropHandle}
on:dragover={(event) => {
event.preventDefault();
}}
on:change={handleChange}
bind:files={pdfFile}
class="bg-gray-200"
accept={'.pdf'}
>
<UploadOutline size="xl"></UploadOutline>
{#if !pdfFile}
<p class="mb-2 text-sm text-gray-500">
<span class="font-semibold">Click to upload</span> or drag and drop
</p>
<p class="text-xs text-gray-500">PDF Format Only (File Size: 30MB)</p>
{:else}
<p>{fileName}</p>
<Button
on:click={() => {
pdfFile = undefined;
}}>Remove</Button
>
{/if}
</Dropzone>
{:else}
<p class="bg-gray-200 p-2 rounded-lg border border-gray-300">Pdf is uploading...</p>
{/if}
</div>
21 changes: 21 additions & 0 deletions apps/client/static/scripts/pdf.worker.min.mjs

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions apps/client/svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ const config = {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
adapter: adapter(),
env: {
dir: '../..'
}
},

extensions: ['.svelte', '.svx']
};

Expand Down
Loading

0 comments on commit 4708a12

Please sign in to comment.