diff --git a/apps/svelte-gravity-forms/.env.example b/apps/svelte-gravity-forms/.env.example new file mode 100644 index 0000000..659423e --- /dev/null +++ b/apps/svelte-gravity-forms/.env.example @@ -0,0 +1,3 @@ +PUBLIC_GF_CONSUMER_KEY= +PUBLIC_GF_CONSUMER_SECRECT= +PUBLIC_GF_API_URL= \ No newline at end of file diff --git a/apps/svelte-gravity-forms/package.json b/apps/svelte-gravity-forms/package.json index 16f3309..d467585 100644 --- a/apps/svelte-gravity-forms/package.json +++ b/apps/svelte-gravity-forms/package.json @@ -36,6 +36,7 @@ "@sveltejs/kit": "^2.0.0", "@sveltejs/package": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@types/crypto-js": "^4.2.1", "@types/eslint": "8.56.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", @@ -63,8 +64,10 @@ "dependencies": { "bits-ui": "^0.13.0", "clsx": "^2.1.0", + "crypto-js": "^4.2.0", "formsnap": "^0.4.2", "lucide-svelte": "^0.304.0", + "oauth-1.0a": "^2.2.6", "sveltekit-superforms": "^1.13.1", "tailwind-merge": "^2.2.0", "tailwind-variants": "^0.1.20", diff --git a/apps/svelte-gravity-forms/src/lib/components/root.svelte b/apps/svelte-gravity-forms/src/lib/components/root.svelte index 6c32234..accb3a9 100644 --- a/apps/svelte-gravity-forms/src/lib/components/root.svelte +++ b/apps/svelte-gravity-forms/src/lib/components/root.svelte @@ -7,14 +7,19 @@ type $$Props = Props; export let formId: $$Props['formId'] = undefined; + export let backendUrl: $$Props['backendUrl'] = undefined; + export let consumerKey: $$Props['consumerKey'] = undefined; + export let consumerSecret: $$Props['consumerSecret'] = undefined; const { methods: { onSubmitForm }, - states: { formSchema, formFields, formObject, isSubmitted, defaultConfirmation }, refs: { formRef } } = setCtx({ - formId: formId + formId: formId, + backendUrl: backendUrl, + consumerKey: consumerKey, + consumerSecret: consumerSecret }); $: form = $formSchema diff --git a/apps/svelte-gravity-forms/src/lib/components/types.ts b/apps/svelte-gravity-forms/src/lib/components/types.ts index 2cbdd64..4ee507b 100644 --- a/apps/svelte-gravity-forms/src/lib/components/types.ts +++ b/apps/svelte-gravity-forms/src/lib/components/types.ts @@ -1,3 +1,6 @@ export type Props = { - formId?: number; + formId: number | undefined; + backendUrl: string | undefined; + consumerKey: string | undefined; + consumerSecret: string | undefined; }; diff --git a/apps/svelte-gravity-forms/src/lib/internal/gf.ts b/apps/svelte-gravity-forms/src/lib/internal/gf.ts index aee4f74..ecc3f6e 100644 --- a/apps/svelte-gravity-forms/src/lib/internal/gf.ts +++ b/apps/svelte-gravity-forms/src/lib/internal/gf.ts @@ -1,6 +1,5 @@ import { onMount } from 'svelte'; import { get, writable } from 'svelte/store'; -import { PUBLIC_GF_API_URL } from '$env/static/public'; import { z, type AnyZodObject } from 'zod'; import { effect, omit, removeUndefined, toWritableStores } from '$lib/internal/helpers/index.js'; @@ -11,13 +10,21 @@ import type { GFFormObjectProps } from './types.js'; import type { HTMLAttributes } from 'svelte/elements'; +import { getClientFormObject, sendSubmission } from './helpers/gf-rest.js'; export type CreateGravityFromsProps = { - formId?: number; + formId?: number | undefined; + backendUrl?: string; + consumerKey?: string; + consumerSecret?: string; }; const defaultProps = { - formId: undefined + formId: undefined, + backendUrl: 'http://localhost:8888/wp-json', + formObjectData: undefined, + consumerKey: undefined, + consumerSecret: undefined }; export function createSvelteGravityFroms(props: CreateGravityFromsProps) { @@ -27,13 +34,20 @@ export function createSvelteGravityFroms(props: CreateGravityFromsProps) { } satisfies CreateGravityFromsProps; // Create writable stores for the form options - const options = toWritableStores(omit({ ...withDefaults })); + const options = toWritableStores( + omit({ + ...withDefaults + }) + ); + + const { formId, backendUrl } = options; // refs const formRef = writable(undefined); const submitButtonRef = writable | undefined>(undefined); // states + const formObject = writable(undefined); const formFields = writable(undefined); const formIdStore = writable(withDefaults.formId); @@ -43,16 +57,23 @@ export function createSvelteGravityFroms(props: CreateGravityFromsProps) { const defaultConfirmation = writable(undefined); const isSubmitted = writable(false); + const consumerKeyStore = writable(withDefaults.consumerKey); + const consumerSecretStore = writable(withDefaults.consumerSecret); + // Fetch form object from Gravity Forms API - async function getFormObject(formId: number) { - const res = await fetch(`${PUBLIC_GF_API_URL}/forms/${formId}`, { method: 'GET' }); - const data = (await res.json()) as GFFormObjectProps; - return data; - } + async function onSubmitForm(req: { [x: string]: unknown }) { + try { + const submit = await sendSubmission(req, backendUrl, formId); - // Handle form submission - async function onSubmitForm(_formData: unknown) { - isSubmitted.set(true); + if (!submit.is_valid) { + throw new Error(submit.message); + } + + isSubmitted.set(true); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + } } // Calculate column span for a field @@ -159,7 +180,12 @@ export function createSvelteGravityFroms(props: CreateGravityFromsProps) { if (!get(formIdStore)) { return; } - const formData = await getFormObject(get(formIdStore)); + const formData = await getClientFormObject( + backendUrl, + formIdStore, + consumerKeyStore, + consumerSecretStore + ); formObject.set(formData); }); @@ -273,7 +299,9 @@ export function createSvelteGravityFroms(props: CreateGravityFromsProps) { formRequiredIndicator, formSubmtiButton, isSubmitted, - defaultConfirmation + defaultConfirmation, + formId, + backendUrl }, methods: { onSubmitForm diff --git a/apps/svelte-gravity-forms/src/lib/internal/helpers/gf-rest.ts b/apps/svelte-gravity-forms/src/lib/internal/helpers/gf-rest.ts new file mode 100644 index 0000000..4f19cd5 --- /dev/null +++ b/apps/svelte-gravity-forms/src/lib/internal/helpers/gf-rest.ts @@ -0,0 +1,64 @@ +import { get, type Writable } from 'svelte/store'; +import type { GFFormObjectProps } from '../types.js'; + +import OAuth from 'oauth-1.0a'; +import CryptoJS from 'crypto-js'; + +export async function sendSubmission( + req: { [x: string]: unknown }, + backendUrl: Writable, + formId: Writable +) { + const res = await fetch(`${get(backendUrl)}gf/v2/forms/${get(formId)}/submissions`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json;charset=UTF-8' + } + }); + const data = await res.json(); + return data; +} + +export async function getClientFormObject( + backendUrl: Writable, + formId: Writable, + consumer_key: Writable, + consumer_secret: Writable +) { + const oauth = new OAuth({ + consumer: { + key: get(consumer_key), + secret: get(consumer_secret) + }, + signature_method: 'HMAC-SHA1', + hash_function(base_string, key) { + return CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64); + } + }); + + // Generate OAuth 1.0 parameters + const oauthData = oauth.authorize({ + url: `${get(backendUrl)}gf/v2/forms/${get(formId)}`, + method: 'GET' + }); + + // Convert OAuth parameters to URL parameters + const params = new URLSearchParams({ + oauth_consumer_key: oauthData.oauth_consumer_key, + oauth_nonce: oauthData.oauth_nonce, + oauth_signature_method: oauthData.oauth_signature_method, + oauth_timestamp: oauthData.oauth_timestamp.toString(), + oauth_version: oauthData.oauth_version, + oauth_signature: oauthData.oauth_signature + }); + + // Append OAuth parameters to URL + const url = `${get(backendUrl)}gf/v2/forms/${get(formId)}?${params.toString()}`; + + const res = await fetch(url, { method: 'GET' }); + // eslint-disable-next-line no-console + console.log(res); + const data = (await res.json()) as GFFormObjectProps; + return data; +} diff --git a/apps/svelte-gravity-forms/src/lib/internal/helpers/store.ts b/apps/svelte-gravity-forms/src/lib/internal/helpers/store.ts index b218637..beda7b0 100644 --- a/apps/svelte-gravity-forms/src/lib/internal/helpers/store.ts +++ b/apps/svelte-gravity-forms/src/lib/internal/helpers/store.ts @@ -1,5 +1,3 @@ -// Ref: https://github.com/huntabyte/vaul-svelte/blob/main/src/lib/internal/helpers/store.ts - import type { Readable, Stores, StoresValues, Updater, Writable } from 'svelte/store'; import { derived, writable } from 'svelte/store'; import { onDestroy, onMount } from 'svelte'; @@ -38,6 +36,7 @@ export function effect( safeOnDestroy(unsub); return unsub; } + /** * A utility function that creates a derived store that automatically * unsubscribes from its dependencies. @@ -133,7 +132,6 @@ export type ToWritableStores> = { }; /** - * * Given an object of properties, returns an object of writable stores * with the same properties and values. */ diff --git a/apps/svelte-gravity-forms/src/lib/internal/types.ts b/apps/svelte-gravity-forms/src/lib/internal/types.ts index aab7514..07562f8 100644 --- a/apps/svelte-gravity-forms/src/lib/internal/types.ts +++ b/apps/svelte-gravity-forms/src/lib/internal/types.ts @@ -58,7 +58,7 @@ export type GFButtonProps = { id?: string; }; -type GFComfirmationProps = { +export type GFComfirmationProps = { type?: string; id?: string; isDefault?: boolean; diff --git a/apps/svelte-gravity-forms/src/routes/+page.svelte b/apps/svelte-gravity-forms/src/routes/+page.svelte index 368b1fb..074d6c1 100644 --- a/apps/svelte-gravity-forms/src/routes/+page.svelte +++ b/apps/svelte-gravity-forms/src/routes/+page.svelte @@ -1,5 +1,15 @@ - + diff --git a/apps/wp/config/.htaccess b/apps/wp/config/.htaccess index 8c6f37a..83f7ef3 100644 --- a/apps/wp/config/.htaccess +++ b/apps/wp/config/.htaccess @@ -14,4 +14,10 @@ RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] -# END WordPress \ No newline at end of file + +# END WordPress + +#allow cors + + Header set Access-Control-Allow-Origin "*" + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f48059..60e0cbe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,12 +30,18 @@ importers: clsx: specifier: ^2.1.0 version: 2.1.0 + crypto-js: + specifier: ^4.2.0 + version: 4.2.0 formsnap: specifier: ^0.4.2 version: 0.4.2(svelte@4.2.8)(sveltekit-superforms@1.13.1)(zod@3.22.4) lucide-svelte: specifier: ^0.304.0 version: 0.304.0(svelte@4.2.8) + oauth-1.0a: + specifier: ^2.2.6 + version: 2.2.6 sveltekit-superforms: specifier: ^1.13.1 version: 1.13.1(@sveltejs/kit@2.0.6)(svelte@4.2.8)(zod@3.22.4) @@ -64,6 +70,9 @@ importers: '@sveltejs/vite-plugin-svelte': specifier: ^3.0.0 version: 3.0.1(svelte@4.2.8)(vite@5.0.10) + '@types/crypto-js': + specifier: ^4.2.1 + version: 4.2.1 '@types/eslint': specifier: 8.56.0 version: 8.56.0 @@ -959,6 +968,10 @@ packages: /@types/cookie@0.6.0: resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + /@types/crypto-js@4.2.1: + resolution: {integrity: sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==} + dev: true + /@types/eslint@8.56.0: resolution: {integrity: sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==} dependencies: @@ -1680,6 +1693,10 @@ packages: shebang-command: 2.0.0 which: 2.0.2 + /crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + dev: false + /css-tree@2.3.1: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -3254,6 +3271,10 @@ packages: path-key: 4.0.0 dev: true + /oauth-1.0a@2.2.6: + resolution: {integrity: sha512-6bkxv3N4Gu5lty4viIcIAnq5GbxECviMBeKR3WX/q87SPQ8E8aursPZUtsXDnxCs787af09WPRBLqYrf/lwoYQ==} + dev: false + /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'}