Website overall
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
.PhoneInputInput {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import emailjs from "@emailjs/browser";
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PhoneInput, { formatPhoneNumber, parsePhoneNumber } from "react-phone-number-input";
|
||||
import 'react-phone-number-input/style.css'
|
||||
import "./ContactForm.css";
|
||||
|
||||
const ContactForm = () => {
|
||||
const { t } = useTranslation();
|
||||
const [phone, setPhone] = useState<string | undefined>(undefined);
|
||||
|
||||
const notify = () => {
|
||||
toast.success(t("contact.toasts.success"));
|
||||
@@ -18,6 +22,10 @@ const ContactForm = () => {
|
||||
const emptyForm = () => {
|
||||
toast.warning(t("contact.toasts.empty"));
|
||||
};
|
||||
|
||||
const invalidCountryCode = () => {
|
||||
toast.error(t("contact.toasts.invalidCountryCode"));
|
||||
};
|
||||
|
||||
const sendEmail = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@@ -28,11 +36,25 @@ const ContactForm = () => {
|
||||
(input as HTMLInputElement).value.trim() === ""
|
||||
);
|
||||
|
||||
if (isEmpty) {
|
||||
if (isEmpty || !phone) { // Check if phone is also empty
|
||||
emptyForm();
|
||||
return;
|
||||
}
|
||||
|
||||
let parsedPhone = parsePhoneNumber(phone);
|
||||
let countryCode = parsedPhone?.countryCallingCode;
|
||||
|
||||
if (!countryCode) {
|
||||
invalidCountryCode();
|
||||
return;
|
||||
}
|
||||
|
||||
// Append phone number to the form
|
||||
const phoneInput = document.createElement("input");
|
||||
phoneInput.setAttribute("type", "hidden");
|
||||
phoneInput.setAttribute("value", `+${countryCode} ${formatPhoneNumber(phone)}`);
|
||||
e.currentTarget.appendChild(phoneInput);
|
||||
|
||||
emailjs
|
||||
.sendForm("service_o7kxotj", "template_f30zlog", e.currentTarget, {
|
||||
publicKey: "vcSOwPedqkRH3nmr9",
|
||||
@@ -49,20 +71,21 @@ const ContactForm = () => {
|
||||
);
|
||||
|
||||
e.currentTarget.reset();
|
||||
setPhone(undefined); // Reset phone state
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-10 mx-5 lg:mx-0 flex justify-center items-center">
|
||||
<div className="mt-10 mx-5 lg:mx-0 flex justify-center items-center">
|
||||
<form onSubmit={sendEmail} className="w-full md:w-auto">
|
||||
<div className="flex flex-col md:flex-row md:gap-3">
|
||||
<input
|
||||
className="form-input"
|
||||
className="form-input flex-1"
|
||||
type="text"
|
||||
name="user_name"
|
||||
placeholder={t("contact.form.name")}
|
||||
/>
|
||||
<input
|
||||
className="form-input"
|
||||
className="form-input flex-1"
|
||||
type="email"
|
||||
name="user_email"
|
||||
placeholder={t("contact.form.email")}
|
||||
@@ -70,17 +93,24 @@ const ContactForm = () => {
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row md:gap-3">
|
||||
<input
|
||||
className="form-input"
|
||||
className="form-input md:w-1/2"
|
||||
type="text"
|
||||
name="user_company"
|
||||
placeholder={t("contact.form.company")}
|
||||
/>
|
||||
<input
|
||||
className="form-input"
|
||||
type="number"
|
||||
name="user_phone"
|
||||
placeholder={t("contact.form.phone")}
|
||||
/>
|
||||
<div className="md:w-1/2 flex items-center">
|
||||
<PhoneInput
|
||||
defaultCountry="PT"
|
||||
placeholder={t("contact.form.phone")}
|
||||
className="form-input placeholder-white w-full"
|
||||
value={phone}
|
||||
onChange={setPhone}
|
||||
inputProps={{
|
||||
name: "user_phone",
|
||||
required: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<input
|
||||
@@ -90,18 +120,17 @@ const ContactForm = () => {
|
||||
placeholder={t("contact.form.question")}
|
||||
></input>
|
||||
|
||||
<textarea
|
||||
<input
|
||||
className="form-input"
|
||||
name="message"
|
||||
placeholder={t("contact.form.message")}
|
||||
rows={6}
|
||||
></textarea>
|
||||
name="user_reference"
|
||||
placeholder={t("contact.form.reference")}
|
||||
></input>
|
||||
</div>
|
||||
|
||||
<div className="flex mt-5 mb-10 lg:mt-12 mx-10 lg:mx-20 rounded-xl bg-gradient-to-br from-gold-light to-gold-dark p-0.5 shadow-lg">
|
||||
<div className="flex mt-5 mb-10 lg:mt-12 mx-10 sm:mx-40 rounded-full bg-gradient-to-br from-gold-light to-gold-dark p-0.5 shadow-lg">
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 font-medium md:px-8 py-3 text-2xl md:text-3xl bg-gradient-to-br from-custom-bglight to-custom-bgdark rounded-xl hover:bg-transparent hover:from-transparent hover:to-transparent transition duration-500"
|
||||
className="flex-1 font-medium md:px-8 py-3 text-2xl md:text-3xl bg-gradient-to-br from-custom-bglight to-custom-bgdark rounded-full hover:bg-transparent hover:from-transparent hover:to-transparent transition duration-500"
|
||||
>
|
||||
{t("contact.form.button")}
|
||||
</button>
|
||||
|
||||
@@ -21,7 +21,7 @@ const Hero = () => {
|
||||
<img className="items-center" src={HeroImg} alt="hero"></img>
|
||||
</div>
|
||||
<div className="justify-center items-center lg:w-1/2 xl:w-1/2">
|
||||
<div className="flex flex-col text-center lg:pt-10 lg:pr-20 lg:text-right 2xl:pr-40">
|
||||
<div className="flex flex-col text-center lg:pt-10 lg:pr-20 lg:text-right">
|
||||
<img
|
||||
src={Stars}
|
||||
alt="hero"
|
||||
@@ -64,7 +64,7 @@ const Hero = () => {
|
||||
{t("hero.subheading.part2")}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex mt-5 lg:mt-12 mx-10 lg:mx-0 lg:ml-auto rounded-xl bg-gradient-to-br from-gold-light to-gold-dark p-0.5 shadow-lg">
|
||||
<div className="flex mt-5 lg:mt-12 mx-10 lg:mx-0 lg:ml-auto rounded-full bg-gradient-to-br from-gold-light to-gold-dark p-0.5 shadow-lg">
|
||||
<a
|
||||
className="flex w-full"
|
||||
href="Contact"
|
||||
@@ -73,7 +73,7 @@ const Hero = () => {
|
||||
handleNavigation("Contact");
|
||||
}}
|
||||
>
|
||||
<button className="flex-1 font-medium md:px-8 py-3 text-2xl md:text-3xl bg-gradient-to-br from-custom-bglight to-custom-bgdark rounded-xl hover:bg-transparent hover:from-transparent hover:to-transparent transition duration-500">
|
||||
<button className="flex-1 font-medium md:px-8 py-3 text-2xl md:text-3xl bg-gradient-to-br from-custom-bglight to-custom-bgdark rounded-full hover:bg-transparent hover:from-transparent hover:to-transparent transition duration-500">
|
||||
{t("hero.button")}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
@@ -16,7 +16,7 @@ const Buttons = ({ changeActiveGroup }: props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="lg:px-40 flex flex-row 2xl:gap-8 gap-2 mx-2 md:gap-5 mt-5 lg:mt-10 mb-4 justify-center">
|
||||
<div className="lg:px-40 mx-5 gap-5 flex flex-row flex-1 2xl:gap-8 md:gap-5 mt-5 lg:mt-10 mb-4 justify-center">
|
||||
<CardBtn
|
||||
title="Marketing"
|
||||
onClick={() => handleClick("markCards")}
|
||||
@@ -33,7 +33,7 @@ const Buttons = ({ changeActiveGroup }: props) => {
|
||||
isSelected={selectedButton === "smCards"}
|
||||
/>
|
||||
<CardBtn
|
||||
title="Camera & Edits"
|
||||
title="Video & Edits"
|
||||
onClick={() => handleClick("camCards")}
|
||||
isSelected={selectedButton === "camCards"}
|
||||
/>
|
||||
|
||||
@@ -9,7 +9,7 @@ const CameraCards = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap gap-4 xl:flex-row mx-4">
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap xl:flex-row mx-4">
|
||||
<Card
|
||||
title={t("services.cards.media.card1.title")}
|
||||
description={t("services.cards.media.card1.description")}
|
||||
|
||||
@@ -6,7 +6,7 @@ interface props {
|
||||
|
||||
const CardBtn = ({ title, onClick, isSelected }: props) => {
|
||||
const buttonClass = isSelected
|
||||
? "w-full font-bold md:px-4 py-1 text-xs lg:text-sm xl:text-2xl cursor-pointer"
|
||||
? "w-full font-bold md:px-4 py-1 text-xs lg:text-sm xl:text-xl cursor-pointer"
|
||||
: "w-full font-medium md:px-4 py-1 text-xs lg:text-sm xl:text-xl text-gray-400 shadow-inner hover:text-text-gold cursor-pointer";
|
||||
|
||||
return (
|
||||
|
||||
@@ -31,7 +31,7 @@ const CardGroup = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full font-medium md:px-8 py-3 text-2xl md:text-3xl bg-gradient-to-br from-custom-bglight to-custom-bgdark rounded-xl flex flex-col">
|
||||
<div className="h-full font-medium md:px-8 py-3 text-2xl md:text-3xl flex flex-col">
|
||||
{ActiveCards && <ActiveCards />}
|
||||
<Buttons changeActiveGroup={changeActiveGroup} />
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ const MarketingCards = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap gap-4 xl:flex-row mx-4">
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap xl:flex-row mx-4">
|
||||
<Card
|
||||
title={t("services.cards.marketing.card1.title")}
|
||||
description={t("services.cards.marketing.card1.description")}
|
||||
|
||||
@@ -8,7 +8,7 @@ interface IProps {
|
||||
const Card = ({ title, description, imgSrc, delay }: IProps) => {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col justify-end flex-1 h-full border-solid border shadow-lg bg-cover bg-center text-center"
|
||||
className="flex flex-col mt-4 lg:mt-0 lg:mr-8 justify-end flex-1 h-full border-solid border shadow-lg bg-cover bg-center text-center"
|
||||
style={{
|
||||
backgroundImage: `url(${imgSrc})`,
|
||||
filter: "saturate(50%)",
|
||||
|
||||
@@ -2,9 +2,9 @@ import CardGroup from "./CardGroup";
|
||||
|
||||
const ServiceCardContainer = () => {
|
||||
return (
|
||||
<div className="h-full xl:h-[65vh] 1920:h-[60vh] rounded-xl mx-4 lg:mx-20 xl:mx-40 2xl:mx-60 1920:margin-calc mt-10 bg-gradient-to-br from-gold-light to-gold-dark p-0.5 shadow-lg ">
|
||||
<div className="h-full xl:h-[65vh] 1920:h-[60vh] rounded-xl mx-4 lg:mx-20 xl:mx-40 2xl:mx-60 1920:margin-calc mt-10 p-0.5 shadow-lg ">
|
||||
<CardGroup />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const SocialMediaCards = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap gap-4 xl:flex-row mx-4">
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap xl:flex-row mx-4">
|
||||
<Card
|
||||
title={t("services.cards.social.card1.title")}
|
||||
description={t("services.cards.social.card1.description")}
|
||||
|
||||
@@ -9,7 +9,7 @@ const WesiteCards = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap gap-4 xl:flex-row mx-4">
|
||||
<div className="h-full flex lg:mt-20 flex-col flex-wrap xl:flex-row mx-4">
|
||||
<Card
|
||||
title={t("services.cards.website.card1.title")}
|
||||
description={t("services.cards.website.card1.description")}
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ body {
|
||||
}
|
||||
|
||||
.form-input {
|
||||
@apply rounded-xl px-4 py-2 mt-2 bg-gray-bg border-solid border border-gray-300 text-sm md:text-lg;
|
||||
@apply rounded-xl px-4 py-4 mt-2 bg-gray-bg border-solid border border-gray-300 text-xs md:text-xl;
|
||||
}
|
||||
|
||||
.gold-text {
|
||||
@@ -50,7 +50,7 @@ body {
|
||||
}
|
||||
|
||||
.results-card-content {
|
||||
@apply mb-2 mt-3 italic text-lg xl:text-2xl font-medium text-gray-300;
|
||||
@apply mb-5 mt-3 italic text-lg xl:text-2xl font-medium text-gray-300;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
|
||||
Reference in New Issue
Block a user