-
Notifications
You must be signed in to change notification settings - Fork 350
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from CriticalMoments/contact_us
Contact Us functionality, including saving to the database
- Loading branch information
Showing
7 changed files
with
285 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { fail } from "@sveltejs/kit" | ||
|
||
/** @type {import('./$types').Actions} */ | ||
export const actions = { | ||
submitContactUs: async ({ request, locals: { supabaseServiceRole } }) => { | ||
const formData = await request.formData() | ||
const errors: { [fieldName: string]: string } = {} | ||
|
||
const firstName = formData.get("first_name")?.toString() ?? "" | ||
if (firstName.length < 2) { | ||
errors["first_name"] = "First name is required" | ||
} | ||
if (firstName.length > 500) { | ||
errors["first_name"] = "First name too long" | ||
} | ||
|
||
const lastName = formData.get("last_name")?.toString() ?? "" | ||
if (lastName.length < 2) { | ||
errors["last_name"] = "Last name is required" | ||
} | ||
if (lastName.length > 500) { | ||
errors["last_name"] = "Last name too long" | ||
} | ||
|
||
const email = formData.get("email")?.toString() ?? "" | ||
if (email.length < 6) { | ||
errors["email"] = "Email is required" | ||
} else if (email.length > 500) { | ||
errors["email"] = "Email too long" | ||
} else if (!email.includes("@") || !email.includes(".")) { | ||
errors["email"] = "Invalid email" | ||
} | ||
|
||
const company = formData.get("company")?.toString() ?? "" | ||
if (company.length > 500) { | ||
errors["company"] = "Company too long" | ||
} | ||
|
||
const phone = formData.get("phone")?.toString() ?? "" | ||
if (phone.length > 100) { | ||
errors["phone"] = "Phone number too long" | ||
} | ||
|
||
const message = formData.get("message")?.toString() ?? "" | ||
if (message.length > 2000) { | ||
errors["message"] = "Message too long (" + message.length + " of 2000)" | ||
} | ||
|
||
console.log("errors:", errors) | ||
if (Object.keys(errors).length > 0) { | ||
return fail(400, { errors }) | ||
} | ||
|
||
// Save to database | ||
const { error: insertError } = await supabaseServiceRole | ||
.from("contact_requests") | ||
.insert({ | ||
first_name: firstName, | ||
last_name: lastName, | ||
email, | ||
company_name: company, | ||
phone, | ||
message_body: message, | ||
updated_at: new Date(), | ||
}) | ||
|
||
if (insertError) { | ||
return fail(500, { errors: { _: "Error saving" } }) | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<script lang="ts"> | ||
import { enhance, applyAction } from "$app/forms" | ||
import type { SubmitFunction } from "@sveltejs/kit" | ||
let errors: { [fieldName: string]: string } = {} | ||
let loading = false | ||
let showSuccess = false | ||
const formFields = [ | ||
{ | ||
id: "first_name", | ||
label: "First Name *", | ||
inputType: "text", | ||
autocomplete: "given-name", | ||
}, | ||
{ | ||
id: "last_name", | ||
label: "Last Name *", | ||
inputType: "text", | ||
autocomplete: "family-name", | ||
}, | ||
{ | ||
id: "email", | ||
label: "Email *", | ||
inputType: "email", | ||
autocomplete: "email", | ||
}, | ||
{ | ||
id: "phone", | ||
label: "Phone Number", | ||
inputType: "tel", | ||
autocomplete: "tel", | ||
}, | ||
{ | ||
id: "company", | ||
label: "Company Name", | ||
inputType: "text", | ||
autocomplete: "organization", | ||
}, | ||
{ | ||
id: "message", | ||
label: "Message", | ||
inputType: "textarea", | ||
autocomplete: "off", | ||
}, | ||
] | ||
const handleSubmit: SubmitFunction = () => { | ||
loading = true | ||
errors = {} | ||
return async ({ update, result }) => { | ||
await update({ reset: false }) | ||
await applyAction(result) | ||
loading = false | ||
console.log(result) | ||
if (result.type === "success") { | ||
showSuccess = true | ||
} else if (result.type === "failure") { | ||
errors = result.data?.errors ?? {} | ||
} else if (result.type === "error") { | ||
errors = { _: "An error occurred. Please check inputs and try again." } | ||
} | ||
} | ||
} | ||
</script> | ||
|
||
<div | ||
class="flex flex-col lg:flex-row mx-auto my-4 min-h-[70vh] place-items-center lg:place-items-start place-content-center" | ||
> | ||
<div | ||
class="max-w-[400px] lg:max-w-[500px] flex flex-col place-content-center p-4 lg:mr-8 lg:mb-8 lg:min-h-[70vh]" | ||
> | ||
<div class="px-6"> | ||
<h1 class="text-2xl lg:text-4xl font-bold mb-4">Contact Us</h1> | ||
<p class="text-lg">Talk to one of our service professionals to:</p> | ||
<ul class="list-disc list-outside pl-6 py-4 space-y-1"> | ||
<li class="">Get a live demo</li> | ||
<li class="">Discuss your specific needs</li> | ||
<li>Get a quote</li> | ||
<li>Answer any technical questions you have</li> | ||
</ul> | ||
<p>Once you complete the form, we'll reach out to you! *</p> | ||
<p class="text-sm pt-8"> | ||
*Not really for this demo page, but you should say something like that | ||
😉 | ||
</p> | ||
</div> | ||
</div> | ||
|
||
<div | ||
class="flex flex-col flex-grow m-4 lg:ml-10 min-w-[300px] stdphone:min-w-[360px] max-w-[400px] place-content-center" | ||
> | ||
{#if showSuccess} | ||
<div class="flex flex-col place-content-center lg:min-h-[70vh]"> | ||
<div | ||
class="card card-bordered shadow-lg py-6 px-6 mx-2 lg:mx-0 lg:p-6 mb-10" | ||
> | ||
<div class="text-2xl font-bold mb-4">Thank you!</div> | ||
<p class="">We've received your message and will be in touch soon.</p> | ||
</div> | ||
</div> | ||
{:else} | ||
<div class="card card-bordered shadow-lg p-4 pt-6 mx-2 lg:mx-0 lg:p-6"> | ||
<form | ||
class="form-widget flex flex-col" | ||
method="POST" | ||
action="?/submitContactUs" | ||
use:enhance={handleSubmit} | ||
> | ||
{#each formFields as field} | ||
<label for={field.id}> | ||
<div class="flex flex-row"> | ||
<div class="text-base font-bold">{field.label}</div> | ||
{#if errors[field.id]} | ||
<div class="text-red-600 flex-grow text-sm ml-2 text-right"> | ||
{errors[field.id]} | ||
</div> | ||
{/if} | ||
</div> | ||
{#if field.inputType === "textarea"} | ||
<textarea | ||
id={field.id} | ||
name={field.id} | ||
autocomplete={field.autocomplete} | ||
rows={4} | ||
class="{errors[field.id] | ||
? 'input-error' | ||
: ''} h-24 input-sm mt-1 input input-bordered w-full mb-3 text-base py-4" | ||
></textarea> | ||
{:else} | ||
<input | ||
id={field.id} | ||
name={field.id} | ||
type={field.inputType} | ||
autocomplete={field.autocomplete} | ||
class="{errors[field.id] | ||
? 'input-error' | ||
: ''} input-sm mt-1 input input-bordered w-full mb-3 text-base py-4" | ||
/> | ||
{/if} | ||
</label> | ||
{/each} | ||
|
||
{#if Object.keys(errors).length > 0} | ||
<p class="text-red-600 text-sm mb-2"> | ||
Please resolve above issues. | ||
</p> | ||
{/if} | ||
|
||
<button class="btn btn-primary {loading ? 'btn-disabled' : ''}" | ||
>{loading ? "Submitting" : "Submit"}</button | ||
> | ||
</form> | ||
</div> | ||
{/if} | ||
</div> | ||
</div> |