fix contact form
Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
parent
b3d3443243
commit
d85a29c15d
10
actions/contact.ts
Normal file
10
actions/contact.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
export default async function contactForm(formData: FormData) {
|
||||||
|
const rawFormData = {
|
||||||
|
name: formData.get('name'),
|
||||||
|
email: formData.get('email'),
|
||||||
|
message: formData.get('message'),
|
||||||
|
};
|
||||||
|
console.log(rawFormData);
|
||||||
|
};
|
@ -1,122 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { User, Award, Globe } from 'lucide-react';
|
|
||||||
import { Button } from '@/components/ui/Button';
|
|
||||||
import { allAuthors } from '@/.content-collections/generated';
|
|
||||||
import Image from 'next/image';
|
|
||||||
|
|
||||||
const TeamMember = ({ name, role, image }) => (
|
|
||||||
<div className="text-center">
|
|
||||||
<Image className="mx-auto h-40 w-40 rounded-full" width={256} height={256} src={image} alt={name} />
|
|
||||||
<div className="mt-4">
|
|
||||||
<h3 className="text-lg font-medium text-gray-900">{name}</h3>
|
|
||||||
<p className="text-sm text-gray-500">{role}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
function shuffle(array) {
|
|
||||||
let currentIndex = array.length;
|
|
||||||
|
|
||||||
// While there remain elements to shuffle...
|
|
||||||
while (currentIndex != 0) {
|
|
||||||
|
|
||||||
// Pick a remaining element...
|
|
||||||
let randomIndex = Math.floor(Math.random() * currentIndex);
|
|
||||||
currentIndex--;
|
|
||||||
|
|
||||||
// And swap it with the current element.
|
|
||||||
[array[currentIndex], array[randomIndex]] = [
|
|
||||||
array[randomIndex], array[currentIndex]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const AboutPage = () => {
|
|
||||||
const teamMembers = allAuthors.map(author => ({
|
|
||||||
name: author.displayName,
|
|
||||||
role: author.role,
|
|
||||||
image: author.avatarUrl,
|
|
||||||
}));
|
|
||||||
shuffle(teamMembers);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bg-gray-100 min-h-screen">
|
|
||||||
<header className="bg-white shadow">
|
|
||||||
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
|
||||||
<h1 className="text-3xl font-bold text-gray-900">About Us</h1>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<div className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
|
||||||
<div className="px-4 py-6 sm:px-0">
|
|
||||||
<div className="text-center mb-12">
|
|
||||||
<h2 className="text-3xl font-extrabold text-gray-900 sm:text-4xl">
|
|
||||||
Empowering Canadian Businesses with Innovative Technology
|
|
||||||
</h2>
|
|
||||||
<p className="mt-4 text-xl text-gray-500">
|
|
||||||
Techaro Computing Canada is at the forefront of digital transformation, helping businesses across the country leverage cutting-edge technology to drive growth and innovation.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-lg mb-12">
|
|
||||||
<div className="px-4 py-5 sm:px-6">
|
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900">Our Mission</h3>
|
|
||||||
</div>
|
|
||||||
<div className="border-t border-gray-200">
|
|
||||||
<dl>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
|
||||||
<User className="h-5 w-5 mr-2 text-blue-500" />
|
|
||||||
Client Focus
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
We are dedicated to understanding and meeting the unique needs of each client, ensuring their success in the digital landscape.
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
|
||||||
<Award className="h-5 w-5 mr-2 text-blue-500" />
|
|
||||||
Innovation
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
We continuously explore and implement the latest technologies to provide cutting-edge solutions for our clients.
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
|
||||||
<Globe className="h-5 w-5 mr-2 text-blue-500" />
|
|
||||||
Canadian Focus
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
We are committed to strengthening the Canadian tech ecosystem and helping local businesses compete on a global scale.
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="text-center mb-12">
|
|
||||||
<h3 className="text-2xl font-bold text-gray-900">Our Team</h3>
|
|
||||||
<div className="mt-10 grid grid-cols-1 gap-10 sm:grid-cols-2 lg:grid-cols-3">
|
|
||||||
{teamMembers.map((member, index) => (
|
|
||||||
<TeamMember key={index} {...member} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-blue-700 rounded-lg shadow-xl overflow-hidden">
|
|
||||||
<div className="px-4 py-5 sm:p-6 text-center">
|
|
||||||
<h3 className="text-2xl font-semibold text-white mb-4">Ready to Transform Your Business?</h3>
|
|
||||||
<p className="text-blue-100 mb-6">Let{"'"}s discuss how Techaro Computing Canada can help you achieve your technology goals.</p>
|
|
||||||
<Button className="bg-white text-blue-700 hover:bg-blue-50">
|
|
||||||
Schedule a Consultation
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AboutPage;
|
|
155
app/about/page.tsx
Normal file
155
app/about/page.tsx
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { User, Award, Globe } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/Button";
|
||||||
|
import { allAuthors } from "@/.content-collections/generated";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
const TeamMember = ({
|
||||||
|
name,
|
||||||
|
role,
|
||||||
|
image,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
image: string;
|
||||||
|
}) => (
|
||||||
|
<div className="text-center">
|
||||||
|
<Image
|
||||||
|
className="mx-auto h-40 w-40 rounded-full"
|
||||||
|
width={256}
|
||||||
|
height={256}
|
||||||
|
src={image}
|
||||||
|
alt={name}
|
||||||
|
/>
|
||||||
|
<div className="mt-4">
|
||||||
|
<h3 className="text-lg font-medium text-gray-900">{name}</h3>
|
||||||
|
<p className="text-sm text-gray-500">{role}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
function shuffle(array: any[]) {
|
||||||
|
let currentIndex = array.length;
|
||||||
|
|
||||||
|
// While there remain elements to shuffle...
|
||||||
|
while (currentIndex != 0) {
|
||||||
|
// Pick a remaining element...
|
||||||
|
let randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
|
currentIndex--;
|
||||||
|
|
||||||
|
// And swap it with the current element.
|
||||||
|
[array[currentIndex], array[randomIndex]] = [
|
||||||
|
array[randomIndex],
|
||||||
|
array[currentIndex],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AboutPage = () => {
|
||||||
|
const teamMembers = allAuthors.map((author) => ({
|
||||||
|
name: author.displayName,
|
||||||
|
role: author.role,
|
||||||
|
image: author.avatarUrl,
|
||||||
|
}));
|
||||||
|
shuffle(teamMembers);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-gray-100 min-h-screen">
|
||||||
|
<header className="bg-white shadow">
|
||||||
|
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||||
|
<h1 className="text-3xl font-bold text-gray-900">About Us</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<div className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
||||||
|
<div className="px-4 py-6 sm:px-0">
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<h2 className="text-3xl font-extrabold text-gray-900 sm:text-4xl">
|
||||||
|
Empowering Canadian Businesses with Innovative Technology
|
||||||
|
</h2>
|
||||||
|
<p className="mt-4 text-xl text-gray-500">
|
||||||
|
Techaro Computing Canada is at the forefront of digital
|
||||||
|
transformation, helping businesses across the country leverage
|
||||||
|
cutting-edge technology to drive growth and innovation.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white shadow overflow-hidden sm:rounded-lg mb-12">
|
||||||
|
<div className="px-4 py-5 sm:px-6">
|
||||||
|
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
||||||
|
Our Mission
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-gray-200">
|
||||||
|
<dl>
|
||||||
|
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
||||||
|
<User className="h-5 w-5 mr-2 text-blue-500" />
|
||||||
|
Client Focus
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
We are dedicated to understanding and meeting the unique
|
||||||
|
needs of each client, ensuring their success in the
|
||||||
|
digital landscape.
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
||||||
|
<Award className="h-5 w-5 mr-2 text-blue-500" />
|
||||||
|
Innovation
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
We continuously explore and implement the latest
|
||||||
|
technologies to provide cutting-edge solutions for our
|
||||||
|
clients.
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
||||||
|
<Globe className="h-5 w-5 mr-2 text-blue-500" />
|
||||||
|
Canadian Focus
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
We are committed to strengthening the Canadian tech
|
||||||
|
ecosystem and helping local businesses compete on a global
|
||||||
|
scale.
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<h3 className="text-2xl font-bold text-gray-900">Our Team</h3>
|
||||||
|
<div className="mt-10 grid grid-cols-1 gap-10 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{teamMembers.map((member, index) => (
|
||||||
|
<TeamMember key={index} {...member} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-blue-700 rounded-lg shadow-xl overflow-hidden">
|
||||||
|
<div className="px-4 py-5 sm:p-6 text-center">
|
||||||
|
<h3 className="text-2xl font-semibold text-white mb-4">
|
||||||
|
Ready to Transform Your Business?
|
||||||
|
</h3>
|
||||||
|
<p className="text-blue-100 mb-6">
|
||||||
|
Let{"'"}s discuss how Techaro Computing Canada can help you
|
||||||
|
achieve your technology goals.
|
||||||
|
</p>
|
||||||
|
<Link href="/contact">
|
||||||
|
<Button className="bg-white text-blue-700 hover:bg-blue-50">
|
||||||
|
Schedule a Consultation
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AboutPage;
|
@ -36,10 +36,10 @@ export default async function Page({ params }: { params: PageParams }) {
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<p className="text-muted-foreground pb-8 mt-4 text-sm max-w-[80ch] mx-auto">
|
<div className="text-muted-foreground pb-8 mt-4 text-sm max-w-[80ch] mx-auto">
|
||||||
<AuthorChip {...page.author!} />
|
<AuthorChip {...page.author!} />
|
||||||
{page.summary}
|
{page.summary}
|
||||||
</p>
|
</div>
|
||||||
|
|
||||||
{page.image !== undefined && (
|
{page.image !== undefined && (
|
||||||
<Image
|
<Image
|
||||||
|
@ -1,51 +1,62 @@
|
|||||||
import React from 'react';
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import contactForm from '@/actions/contact';
|
||||||
|
|
||||||
const ContactPage = () => {
|
const ContactPage = () => {
|
||||||
async function contactForm(formData) {
|
const [message, setMessage] = useState(null);
|
||||||
"use server";
|
|
||||||
const rawFormData = {
|
const callback = async (formData) => {
|
||||||
name: formData.get('name'),
|
await contactForm(formData);
|
||||||
email: formData.get('email'),
|
setMessage("Our intrepid team of code monkeys will be looking at this as soon as possible!");
|
||||||
message: formData.get('message'),
|
}
|
||||||
};
|
|
||||||
console.log(rawFormData);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-100 mx-auto text-gray-900 px-4 pt-8">
|
<>
|
||||||
<h1 className="text-3xl font-bold text-gray-900 mb-6">Contact Techaro Computing Canada</h1>
|
<header className="bg-white shadow">
|
||||||
|
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<h1 className="text-3xl font-bold text-gray-900">Contact Us</h1>
|
||||||
<div className="text-gray-900">
|
|
||||||
<h2 className="text-xl font-semibold mb-4">Get in Touch</h2>
|
|
||||||
<p className="mb-4">We would love to hear from you. Please fill out the form below or use our contact information.</p>
|
|
||||||
|
|
||||||
<h3 className="text-lg font-semibold mb-2">Contact Information</h3>
|
|
||||||
<p>Email: sales@techaro.lol</p>
|
|
||||||
<p>Phone: (123) 456-7890</p>
|
|
||||||
<p>Address: 123 Tech Street, Toronto, ON M5V 1J2</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
<div className="bg-gray-100 mx-auto text-gray-900 px-4 pt-8">
|
||||||
|
<div className="grid grid-cols-1 gap-8 max-w-3xl mx-auto">
|
||||||
|
<div className="text-gray-900">
|
||||||
|
<h2 className="text-xl font-semibold mb-4">Get in Touch</h2>
|
||||||
|
<p className="mb-4">We would love to hear from you. Please fill out the form below or use our contact information.</p>
|
||||||
|
|
||||||
<div className="pb-4">
|
<h3 className="text-lg font-semibold mb-2">Contact Information</h3>
|
||||||
<h2 className="text-xl font-semibold mb-4">Contact Form</h2>
|
<p>Email: sales@techaro.lol</p>
|
||||||
<form className="space-y-4" action={contactForm}>
|
</div>
|
||||||
<div>
|
|
||||||
<label htmlFor="name" className="block mb-1">Name</label>
|
<div className="pb-4">
|
||||||
<input disabled type="text" id="name" name="name" className="w-full px-3 py-2 border rounded" required />
|
<h2 className="text-xl font-semibold mb-4">Contact Form</h2>
|
||||||
</div>
|
<form className="space-y-4" action={callback}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="email" className="block mb-1">Email</label>
|
<label htmlFor="name" className="block mb-1">Name</label>
|
||||||
<input disabled type="email" id="email" name="email" className="w-full px-3 py-2 border rounded" required />
|
<input type="text" id="name" name="name" className="w-full px-3 py-2 border rounded" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="message" className="block mb-1">Message</label>
|
<label htmlFor="email" className="block mb-1">Email</label>
|
||||||
<textarea disabled id="message" name="message" rows="4" className="w-full px-3 py-2 border rounded" required></textarea>
|
<input type="email" id="email" name="email" className="w-full px-3 py-2 border rounded" required />
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" disabled className="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600">Send Message</button>
|
<div>
|
||||||
</form>
|
<label htmlFor="message" className="block mb-1">Message</label>
|
||||||
|
<textarea id="message" name="message" rows="4" className="w-full px-3 py-2 border rounded" required></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">Send Message</button>
|
||||||
|
{message !== null && (
|
||||||
|
<>
|
||||||
|
<div className="p-4 bg-gray-200">
|
||||||
|
<p className="text-xl">Thanks!</p>
|
||||||
|
<p className="p-4">{message}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ const authors = defineCollection({
|
|||||||
schema: (z) => ({
|
schema: (z) => ({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
displayName: z.string(),
|
displayName: z.string(),
|
||||||
|
active: z.boolean().default(true),
|
||||||
role: z.string(),
|
role: z.string(),
|
||||||
avatarUrl: z.string(),
|
avatarUrl: z.string(),
|
||||||
bluesky: z.string().optional(),
|
bluesky: z.string().optional(),
|
||||||
|
@ -4,4 +4,5 @@ displayName: "Mimi Yasomi"
|
|||||||
role: "Member of Technical Staff"
|
role: "Member of Technical Staff"
|
||||||
avatarUrl: /img/avatars/mimi.webp
|
avatarUrl: /img/avatars/mimi.webp
|
||||||
bluesky: yasomi.xeiaso.net
|
bluesky: yasomi.xeiaso.net
|
||||||
|
active: true
|
||||||
---
|
---
|
||||||
|
Loading…
x
Reference in New Issue
Block a user