feat: /contact page on classroomio-com (#428)
* contact page v1 * finished the UI of the contact us page * working on the forms * All functions and logic done * some refactor * some refactor * some refactor * some refactor * added loading icon * removed the image * finished the send email * some cleanup * chore: refactoring * finishing touches * update .env.example --------- Co-authored-by: emmanuel <[email protected]>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
PUBLIC_ENABLE_FAQ=1
|
||||
PUBLIC_ENABLE_USERS_COMPANIES=
|
||||
PUBLIC_ENABLE_STATS=
|
||||
PUBLIC_ENABLE_STATS=
|
||||
PUBLIC_SERVER_URL=
|
||||
@@ -0,0 +1,22 @@
|
||||
<script>
|
||||
import Renew from 'carbon-icons-svelte/lib/Renew.svelte';
|
||||
export let label = '';
|
||||
export let className = '';
|
||||
export let isLoading = false;
|
||||
export let isDisabled = false;
|
||||
export let onClick = () => {};
|
||||
</script>
|
||||
|
||||
<div class="w-full flex items-center justify-center pt-5">
|
||||
<button
|
||||
class="bg-[#0233BD] text-white font-medium text-sm py-4 {className}"
|
||||
disabled={isDisabled}
|
||||
on:click={onClick}
|
||||
>
|
||||
{#if isLoading}
|
||||
<Renew size={24} class="animate-spin" />
|
||||
{:else}
|
||||
{label}
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script>
|
||||
import Button from '$lib/Button/Button.svelte';
|
||||
import TextArea from '$lib/Input/TextArea.svelte';
|
||||
import TextField from '$lib/Input/TextField.svelte';
|
||||
import { isFormValid } from '$lib/utils/isFormValid';
|
||||
import { submitForm } from '$lib/utils/submitForm';
|
||||
import Sucess from '$lib/Contact/Sucess.svelte';
|
||||
|
||||
let name = '';
|
||||
let email = '';
|
||||
let title = '';
|
||||
let description = '';
|
||||
|
||||
let isLoading = false;
|
||||
let errorMessage = '';
|
||||
let sent = false;
|
||||
|
||||
const handleClick = async () => {
|
||||
const data = { name, email, title, description };
|
||||
|
||||
if (!isFormValid(data)) {
|
||||
errorMessage = 'Please fill out all required fields.';
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
|
||||
const formData = {
|
||||
title: `[FEEDBACK] ${title}`,
|
||||
description: `My name is ${JSON.stringify(name)}, email is ${JSON.stringify(
|
||||
email
|
||||
)}. \n\n${JSON.stringify(description)}.`,
|
||||
replyTo: email
|
||||
};
|
||||
|
||||
try {
|
||||
await submitForm(formData);
|
||||
sent = true;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if sent}
|
||||
<Sucess />
|
||||
{:else}
|
||||
<div class="w-full my-10 space-y-5">
|
||||
<div class="flex flex-col md:flex-row gap-10">
|
||||
<TextField label="Your Name" isRequired className="w-full" bind:value={name} />
|
||||
<TextField label="Your Email" isRequired className="w-full" bind:value={email} />
|
||||
</div>
|
||||
<TextField label="Subject" isRequired bind:value={title} />
|
||||
<TextArea label="Message" isRequired bind:value={description} />
|
||||
{#if !!errorMessage}
|
||||
<p class="text-left text-sm text-red-500">{errorMessage}</p>
|
||||
{/if}
|
||||
<Button
|
||||
label="Submit"
|
||||
className="px-32"
|
||||
onClick={handleClick}
|
||||
isDisabled={isLoading}
|
||||
{isLoading}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1,70 @@
|
||||
<script>
|
||||
import Button from '$lib/Button/Button.svelte';
|
||||
import TextArea from '$lib/Input/TextArea.svelte';
|
||||
import TextField from '$lib/Input/TextField.svelte';
|
||||
import { isFormValid } from '$lib/utils/isFormValid';
|
||||
import { submitForm } from '$lib/utils/submitForm';
|
||||
import Sucess from './Sucess.svelte';
|
||||
|
||||
let name = '';
|
||||
let email = '';
|
||||
let title = '';
|
||||
let description = '';
|
||||
|
||||
let isLoading = false;
|
||||
let errorMessage = '';
|
||||
let sent = false;
|
||||
|
||||
async function handleClick() {
|
||||
const data = { name, email, title, description };
|
||||
|
||||
if (!isFormValid(data)) {
|
||||
errorMessage = 'Please fill out all required fields.';
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
|
||||
const formData = {
|
||||
title: `[HELP] ${title}`,
|
||||
description: `My name is ${JSON.stringify(name)}, email is ${JSON.stringify(
|
||||
email
|
||||
)}. \n\n${JSON.stringify(description)}.`,
|
||||
replyTo: email
|
||||
};
|
||||
|
||||
try {
|
||||
await submitForm(formData);
|
||||
sent = true;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if sent}
|
||||
<Sucess />
|
||||
{:else}
|
||||
<div class="w-full my-10 space-y-5">
|
||||
<div class="flex flex-col md:flex-row gap-10">
|
||||
<TextField label="Your Name" isRequired className="w-full" bind:value={name} />
|
||||
<TextField label="Your Email" isRequired className="w-full" bind:value={email} />
|
||||
</div>
|
||||
<TextField label="Subject" isRequired bind:value={title} />
|
||||
<TextArea label="Message" isRequired bind:value={description} />
|
||||
{#if !!errorMessage}
|
||||
<p class="text-left text-sm text-red-500">{errorMessage}</p>
|
||||
{/if}
|
||||
<Button
|
||||
label="Submit"
|
||||
className="px-32"
|
||||
onClick={handleClick}
|
||||
isDisabled={isLoading}
|
||||
{isLoading}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import Button from '$lib/Button/Button.svelte';
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="relative overflow-hidden mt-10 flex space-y-3 flex-col text-center items-center border border-[#D9E0F5] justify-center w-full rounded-md min-h-[300px] p-4 bg-[#F5F8FE]"
|
||||
>
|
||||
<div class="absolute w-20 h-20 bg-[#0233BD] -top-14 -left-9 rotate-[50deg]" />
|
||||
<h1 class="font-bold text-3xl">Your message has been sent 🎉</h1>
|
||||
<p class="w-[70%] font-normal text-sm">
|
||||
We'll get back to you as soon as possible. In the meantime, Explore and enjoy features on our
|
||||
website
|
||||
</p>
|
||||
<Button label="Go to Home" className="px-10 md:px-20" onClick={() => goto('/')} />
|
||||
</div>
|
||||
@@ -98,6 +98,11 @@
|
||||
Resources
|
||||
</p>
|
||||
<ul class="space-y-2 lg:space-y-4">
|
||||
<li
|
||||
class="lg:text-base text-sm leading-6 tracking-wide text-gray-600 hover:text-gray-900"
|
||||
>
|
||||
<a href="/contact">Contact us</a>
|
||||
</li>
|
||||
<li
|
||||
class="lg:text-base text-sm leading-6 tracking-wide text-gray-600 hover:text-gray-900"
|
||||
>
|
||||
|
||||
@@ -130,8 +130,9 @@
|
||||
<a
|
||||
href="/#customization"
|
||||
class="px-6 py-2 border-[1.5px] border-[#0233BD] rounded-[4px] bg-white text-[#0233BD] text-lg font-bold"
|
||||
>Customizable LMS</a
|
||||
>
|
||||
Customizable LMS
|
||||
</a>
|
||||
|
||||
<svg
|
||||
class="absolute -right-1 -bottom-2.5"
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
export let label = '';
|
||||
export let disabled = false;
|
||||
export let placeholder = '';
|
||||
export let value = '';
|
||||
export let rows = 3;
|
||||
export let className = '';
|
||||
export let labelClassName = '';
|
||||
export let bgColor = 'bg-gray-50 focus:bg-primary-50 dark:bg-neutral-700 dark:text-white';
|
||||
export let helperMessage = '';
|
||||
export let errorMessage = '';
|
||||
export let isRequired = false;
|
||||
export let onChange = () => {}; // This is to know if element is 'dirty'
|
||||
export let ref = null;
|
||||
</script>
|
||||
|
||||
<label for="text-field" class="block w-full relative {className}">
|
||||
{#if label}
|
||||
<p class="dark:text-white text-left w-full flex items-center justify-between {labelClassName}">
|
||||
<span>
|
||||
{label}
|
||||
{#if isRequired}
|
||||
<span class="text-red-700">*</span>
|
||||
{/if}
|
||||
</span>
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<textarea
|
||||
{disabled}
|
||||
{rows}
|
||||
{placeholder}
|
||||
bind:value
|
||||
bind:this={ref}
|
||||
required={isRequired}
|
||||
class="form-textarea p-2 border-l-0 border-r-0 border-t-0 border-b-2 border-gray-200 dark:border-neutral-600 focus:border-l-0 focus:border-r-0 rounded-t-md focus:border-t-0 focus:border-b-2 focus:border-primary-600 mt-1 block w-full
|
||||
{bgColor} {!!errorMessage ? 'border-red-500' : 'border-gray-300'}"
|
||||
on:change={onChange}
|
||||
/>
|
||||
{#if !!errorMessage}
|
||||
<p class="text-sm text-red-500">
|
||||
{errorMessage}
|
||||
</p>
|
||||
{:else if helperMessage}
|
||||
<p class="text-sm text-gray-500 dark:text-white">
|
||||
{helperMessage}
|
||||
</p>
|
||||
{/if}
|
||||
<slot name="iconbutton" />
|
||||
</label>
|
||||
|
||||
<style>
|
||||
.form-textarea {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let label = '';
|
||||
export let placeholder = '';
|
||||
export let value: string | number | null = null;
|
||||
export let name = '';
|
||||
export let className = '';
|
||||
export let inputClassName = '';
|
||||
export let labelClassName = '';
|
||||
export let bgColor = 'bg-gray-100 focus:bg-primary-50 dark:bg-neutral-700 dark:text-white';
|
||||
export let autoFocus = false;
|
||||
export let isRequired = false;
|
||||
export let isDisabled = false;
|
||||
export let errorMessage = '';
|
||||
export let helperMessage = '';
|
||||
export let autoComplete = true;
|
||||
|
||||
let ref: HTMLInputElement | undefined = undefined;
|
||||
let focusClass = '';
|
||||
|
||||
onMount(() => {
|
||||
if (autoFocus && ref) {
|
||||
ref.focus();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<label class="block relative {className}">
|
||||
{#if label}
|
||||
<p class=" dark:text-white text-left m-0 {labelClassName}">
|
||||
{label}
|
||||
{#if isRequired}
|
||||
<span class="text-red-700">*</span>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<input
|
||||
class="form-input border-l-0 border-r-0 border-t-0 border-b-2 border-gray-200 dark:border-neutral-600 focus:border-l-0 focus:border-r-0 rounded-t-md focus:border-t-0 focus:border-b-2 {inputClassName} {focusClass} {isDisabled &&
|
||||
'hover:cursor-not-allowed opacity-50'} dark:text-black p-2 mt-1 block w-full {bgColor} {errorMessage
|
||||
? 'border-red-600'
|
||||
: ''}"
|
||||
{placeholder}
|
||||
bind:value
|
||||
bind:this={ref}
|
||||
required={isRequired}
|
||||
disabled={isDisabled}
|
||||
autocomplete={autoComplete ? 'on' : 'off'}
|
||||
on:blur={(e) => {
|
||||
if (focusClass.includes('border-primary-600')) {
|
||||
focusClass = focusClass.replace('border-primary-600', '');
|
||||
}
|
||||
}}
|
||||
on:focus={() => (focusClass += ' border-primary-600')}
|
||||
{name}
|
||||
/>
|
||||
{#if errorMessage}
|
||||
<p class="text-sm text-red-500">{errorMessage}</p>
|
||||
{:else if helperMessage}
|
||||
<p class="dark:text-white text-sm">
|
||||
{helperMessage}
|
||||
</p>
|
||||
{/if}
|
||||
</label>
|
||||
|
||||
<style>
|
||||
.form-input {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.password-eye {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 6px;
|
||||
}
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@
|
||||
</script>
|
||||
|
||||
<header
|
||||
class="hero-bg lg:min-h-[30rem] mt-[10%] md:mt-16 pt-24 pb-16 w-full border-b border-slate-100 {className}"
|
||||
class="hero-bg lg:min-h-[20rem] mt-[10%] md:mt-16 pt-24 pb-16 w-full border-b border-slate-100 {className}"
|
||||
>
|
||||
<slot />
|
||||
</header>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<script lang="ts">
|
||||
import ImageCopy from 'carbon-icons-svelte/lib/ImageCopy.svelte';
|
||||
import TrashCan from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
||||
|
||||
export let imageURL = '';
|
||||
export let label = '';
|
||||
export let isRequired = false;
|
||||
export let labelClassName = '';
|
||||
let isUploading = false;
|
||||
let fileInput: HTMLInputElement;
|
||||
|
||||
const onFileSelected = () => {
|
||||
const file = fileInput?.files?.[0];
|
||||
const sizeInkb = file?.size! / 1024;
|
||||
if (sizeInkb > 500) {
|
||||
return;
|
||||
}
|
||||
if (file) {
|
||||
let reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onloadend = () => {
|
||||
imageURL = reader.result as string;
|
||||
};
|
||||
}
|
||||
};
|
||||
const deleteImage = () => {
|
||||
imageURL = '';
|
||||
if (fileInput) {
|
||||
fileInput.value = '';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div>
|
||||
{#if label}
|
||||
<p class="dark:text-white text-left w-full flex items-center justify-between {labelClassName}">
|
||||
<span>
|
||||
{label}
|
||||
{#if isRequired}
|
||||
<span class="text-red-700">*</span>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
{#if imageURL}
|
||||
<span title="clear image" on:click={deleteImage}>
|
||||
<TrashCan class="fill-red-500 " />
|
||||
</span>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
<div
|
||||
class="flex items-center justify-center w-full border rounded-md min-h-[200px] p-4"
|
||||
on:click={() => fileInput.click()}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
style="display: none;"
|
||||
bind:this={fileInput}
|
||||
on:change={onFileSelected}
|
||||
disabled={isUploading}
|
||||
required={isRequired}
|
||||
/>
|
||||
{#if imageURL}
|
||||
<img src={imageURL} alt="selected file" class="w-[30%] h-auto mt-4" />
|
||||
{:else}
|
||||
<div class="space-y-4">
|
||||
<ImageCopy size={24} class="mx-auto" />
|
||||
<p class="text-center text-sm text-gray-500 my-2">
|
||||
Max file size: 10MB, accepted: jpeg, jpg, png, gif
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -19,3 +19,12 @@ export type OssFriend = {
|
||||
description: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
export type FORM_TYPE_KEY = keyof typeof FORM_TYPE;
|
||||
|
||||
export enum FORM_TYPE {
|
||||
BUG = 'BUG',
|
||||
HELP = 'HELP',
|
||||
FEATURE = 'FEATURE',
|
||||
FEEDBACK = 'FEEDBACK'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export const isFormValid = (data: { [x: string]: any }) => {
|
||||
for (const key in data) {
|
||||
if (!data[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
export const submitForm = async (formData: any) => {
|
||||
try {
|
||||
const response = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to submit the form');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Response from API:', data);
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
import { PUBLIC_SERVER_URL } from '$env/static/public';
|
||||
|
||||
const sendEmail = async (subject: string, content: string, replyTo?: string) => {
|
||||
try {
|
||||
const response = await fetch(`${PUBLIC_SERVER_URL}/sendEmail`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify([
|
||||
{
|
||||
from: `"ClassroomIO Support" <[email protected]>`,
|
||||
to: '[email protected]',
|
||||
subject,
|
||||
content,
|
||||
replyTo
|
||||
}
|
||||
])
|
||||
});
|
||||
|
||||
const responseData = await response.json();
|
||||
console.log('Emails sent successfully:', responseData);
|
||||
|
||||
return 'sent';
|
||||
} catch (error) {
|
||||
console.error('Error sending email', error);
|
||||
return 'failed';
|
||||
}
|
||||
};
|
||||
|
||||
export async function POST({ request }) {
|
||||
try {
|
||||
const { title, description, replyTo } = await request.json();
|
||||
console.log(title, description, replyTo);
|
||||
const result = await sendEmail(title, description, replyTo);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
message: 'Issue created successfully',
|
||||
issue: result
|
||||
}),
|
||||
{
|
||||
status: 201,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log('errors from backend', error);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
message: 'Failed to create issue',
|
||||
error: (error as Error)?.message
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export const prerender = true;
|
||||
@@ -0,0 +1,106 @@
|
||||
<script lang="ts">
|
||||
import ArrowUpRight from 'carbon-icons-svelte/lib/ArrowUpRight.svelte';
|
||||
import PageHeader from '$lib/PageHeader/PageHeader.svelte';
|
||||
|
||||
import FeedbackForm from '$lib/Contact/FeedbackForm.svelte';
|
||||
import HelpForm from '$lib/Contact/HelpForm.svelte';
|
||||
import { FORM_TYPE } from '$lib/types';
|
||||
import type { FORM_TYPE_KEY } from '$lib/types';
|
||||
|
||||
let currentForm: FORM_TYPE_KEY;
|
||||
|
||||
const formList = [
|
||||
{
|
||||
id: FORM_TYPE.BUG,
|
||||
title: '🐜 I want to report a bug',
|
||||
to: 'https://github.com/classroomio/classroomio/issues/new?assignees=&labels=bug&projects=&template=bug-report.yml'
|
||||
},
|
||||
{
|
||||
id: FORM_TYPE.HELP,
|
||||
title: '🙋♂️ I need help'
|
||||
},
|
||||
{
|
||||
id: FORM_TYPE.FEATURE,
|
||||
title: '📮 I want to request a feature',
|
||||
to: 'https://github.com/classroomio/classroomio/issues/new?assignees=&labels=&projects=&template=feature-request.yml'
|
||||
},
|
||||
{
|
||||
id: FORM_TYPE.FEEDBACK,
|
||||
title: '💭 I have feedback'
|
||||
}
|
||||
];
|
||||
|
||||
const onChange = (form: FORM_TYPE_KEY, to?: string) => {
|
||||
currentForm = form;
|
||||
|
||||
if (to) {
|
||||
window.open(to, '_blank');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Contact us | ClassroomIO</title>
|
||||
</svelte:head>
|
||||
|
||||
<section>
|
||||
<PageHeader className="flex flex-col items-center justify-center bg-[#F5F8FE] text-center">
|
||||
<div class="mb-2 ml-[5%] lg:ml-0 flex w-full items-center justify-center">
|
||||
<span
|
||||
style="color: rgb(75, 85, 99);"
|
||||
class="rounded-full border-2 border-[#C2D2FF] px-4 py-1 text-sm font-medium bg-[#DCE5FF] text-blue-700"
|
||||
>
|
||||
Contact Us
|
||||
</span>
|
||||
</div>
|
||||
<h1
|
||||
class="mx-auto text-4xl md:text-7xl lg:text-6xl font-bold text-slate-900 flex flex-col items-center"
|
||||
>
|
||||
<span>Get in touch with <span class="text-blue-700">Us</span></span>
|
||||
</h1>
|
||||
<p
|
||||
class="w-[90%] md:w-[60%] max-w-3xl text-center font-normal text-lg text-slate-700 mt-10 lg:mt-7"
|
||||
>
|
||||
Report any bugs you encounter, request new features you'd like to see, or ask any questions
|
||||
you have about ClassroomIO
|
||||
</p>
|
||||
</PageHeader>
|
||||
|
||||
<div class="my-20 mx-auto">
|
||||
<!-- Content here -->
|
||||
<div
|
||||
class="mx-auto w-[90%] lg:w-[60%] place-items-center grid grid-cols-1 md:grid-cols-2 gap-10"
|
||||
>
|
||||
{#each formList as list}
|
||||
<button
|
||||
on:click={() => onChange(list.id, list.to)}
|
||||
class="text-start border-[1.5px] w-full rounded-md p-3 {currentForm === list.id
|
||||
? `border-[#0233BD]`
|
||||
: `border-gray-200`} flex items-center justify-between"
|
||||
>
|
||||
<p class="text-lg text-slate-700 font-normal">{list.title}</p>
|
||||
{#if list.to}
|
||||
<ArrowUpRight size={16} />
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if currentForm === FORM_TYPE[currentForm]}
|
||||
<div class="mx-auto w-[90%] lg:w-[60%] px-5">
|
||||
{#if currentForm === FORM_TYPE.HELP}
|
||||
<HelpForm />
|
||||
{:else if currentForm === FORM_TYPE.FEEDBACK}
|
||||
<FeedbackForm />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<!-- <PageSignupCTA
|
||||
header="Scale your Teaching Business in Minutes"
|
||||
subText="Don't wait, let's get you started."
|
||||
btnLabel="Register"
|
||||
link="/teach/register"
|
||||
demo={false}
|
||||
/> -->
|
||||
</div>
|
||||
</section>
|
||||
Reference in New Issue
Block a user