open modal

This commit is contained in:
2025-05-14 11:16:35 -03:00
parent 2370630ef1
commit 00f62bee82
8 changed files with 147 additions and 53 deletions

View File

@@ -39,7 +39,7 @@ export const config: CookieConsentConfig = {
// function gtag(...args: any[]) { // function gtag(...args: any[]) {
// window.dataLayer.push(args); // window.dataLayer.push(args);
// } // }
//
// gtag("consent", "update", { // gtag("consent", "update", {
// ad_storage: "granted", // ad_storage: "granted",
// ad_user_data: "granted", // ad_user_data: "granted",

View File

@@ -1,6 +1,7 @@
import { createElement, useEffect } from "react"; import { createElement, useEffect, forwardRef } from "react";
import { Form, useForm } from "react-hook-form"; import { Form, useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { PatternFormat } from "react-number-format";
import clsx from "clsx"; import clsx from "clsx";
import { z } from "zod"; import { z } from "zod";
@@ -20,6 +21,9 @@ const schema = z.object({
export default function Contact({ url }) { export default function Contact({ url }) {
const { register, formState, control, reset, setValue } = useForm({ const { register, formState, control, reset, setValue } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: {
telephone: "",
},
}); });
useEffect(() => { useEffect(() => {
@@ -70,10 +74,23 @@ export default function Contact({ url }) {
</Control> </Control>
<Control> <Control>
<Controller
control={control}
name="telephone"
defaultValue=""
render={({ field: { ref, ...props } }) => {
return (
<Input <Input
aria-invalid={!!formState.errors?.name} aria-invalid={!!formState.errors?.name}
as={PatternFormat}
placeholder="Telefone" placeholder="Telefone"
{...register("telephone")} format="+55 (##) ### ### ###"
getInputRef={ref}
mask="_"
{...props}
/>
);
}}
/> />
<Error>{formState.errors.telephone?.message}</Error> <Error>{formState.errors.telephone?.message}</Error>
</Control> </Control>
@@ -100,15 +117,22 @@ export default function Contact({ url }) {
<button <button
type="submit" type="submit"
className="p-2.5 border border-lime-400 rounded-lg cursor-pointer" className="p-2.5 border border-lime-400 rounded-lg cursor-pointer disabled:border-white/10 disabled:pointer-events-none relative overflow-hidden group"
disabled={formState.isSubmitting}
> >
Enviar <div className="absolute inset-0 hidden group-disabled:flex items-center justify-center bg-black">
<Spinner className="size-6 animate-spin" />
</div>
<>Enviar</>
</button> </button>
</Form> </Form>
); );
} }
export function Input({ as = "input", className, children, ...props }) { export const Input = forwardRef(function Input(
{ as = "input", className, children, ...props },
ref,
) {
return createElement( return createElement(
as, as,
{ {
@@ -119,11 +143,12 @@ export function Input({ as = "input", className, children, ...props }) {
"aria-invalid:border-red-600", "aria-invalid:border-red-600",
className, className,
), ),
ref,
...props, ...props,
}, },
children, children,
); );
} });
function Control({ children, className }) { function Control({ children, className }) {
return <label className={className}>{children}</label>; return <label className={className}>{children}</label>;
@@ -138,3 +163,28 @@ function Error({ children, className }) {
return null; return null;
} }
function Spinner(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
{...props}
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
);
}

View File

@@ -9,15 +9,16 @@ const currency = new Intl.NumberFormat("pt-BR", {
<buy-dropdown class:list={[Astro.props.class]}> <buy-dropdown class:list={[Astro.props.class]}>
<details class="group/dropdown"> <details class="group/dropdown">
<summary <summary
class="flex bg-black hover:bg-white hover:text-black font-semibold py-2.5 px-3 rounded-md cursor-pointer transition class="flex bg-black hover:bg-white hover:text-black font-semibold
py-2.5 px-3 rounded-md cursor-pointer transition
group-open/dropdown:text-black group-open/dropdown:bg-white" group-open/dropdown:text-black group-open/dropdown:bg-white"
> >
Contratar agora Contratar agora
</summary> </summary>
<form <form
class="absolute inset-x-2.5 translate-y-1.5 class="absolute inset-x-2.5 translate-y-1.5
md:inset-auto md:right-2.5 2xl:right-0 md:inset-auto md:right-2.5 md:min-w-96 2xl:right-0
md:min-w-96 bg-stone-900 border border-white/15 rounded-xl shadow-lg" bg-stone-900 border border-white/15 rounded-xl shadow-lg"
> >
<h6 <h6
class="p-2.5 lg:px-5 lg:py-3.5 font-semibold border-b border-white/10 bg-white/5" class="p-2.5 lg:px-5 lg:py-3.5 font-semibold border-b border-white/10 bg-white/5"
@@ -33,15 +34,15 @@ const currency = new Intl.NumberFormat("pt-BR", {
class="box-content size-1.5 border-5 border-black bg-black appearance-none rounded-full ring-1 ring-white/15 checked:border-lime-400 checked:ring-lime-400 mt-1.5" class="box-content size-1.5 border-5 border-black bg-black appearance-none rounded-full ring-1 ring-white/15 checked:border-lime-400 checked:ring-lime-400 mt-1.5"
name="selected" name="selected"
type="radio" type="radio"
value={} value="SINGLE"
checked checked
/> />
<div> <div>
<p class="uppercase font-semibold"> <p class="uppercase font-semibold">
Matrícula única <span Matrícula única
class="px-0.5 text-black bg-lime-400" <span class="px-0.5 text-black bg-lime-400">
>{currency}</span {currency}
> </span>
</p> </p>
<p class="text-sm text-white/50"> <p class="text-sm text-white/50">
Contratação rápida e sem burocracia Contratação rápida e sem burocracia
@@ -134,6 +135,35 @@ const currency = new Intl.NumberFormat("pt-BR", {
connectedCallback() { connectedCallback() {
document.addEventListener("click", this.handleClickOutside); document.addEventListener("click", this.handleClickOutside);
const form = this.querySelector("form") as HTMLFormElement;
form.addEventListener("submit", (e) => {
e.preventDefault();
const radio = form.querySelector(
"input[type=radio]:checked",
) as HTMLInputElement;
if (radio.value === "SINGLE") {
return;
}
// Dispatch a custom event with the selected solution,
// so a React component can listen to it using `window.addEventListener`.
window.dispatchEvent(
new CustomEvent("custom_event:react_form", {
detail: radio.value,
}),
);
window.dispatchEvent(
new CustomEvent("modal:open", {
detail: document.querySelector(
"#solutionmodal",
) as HTMLDialogElement,
}),
);
});
} }
disconnectedCallback() { disconnectedCallback() {

View File

@@ -1,17 +1,7 @@
--- ---
import Container from "~/components/Container.astro"; import Container from "~/components/Container.astro";
import Contact from "./Contact.jsx";
import Modal from "~/components/Modal.astro";
--- ---
{/* Modal */}
<Modal id="planform">
<h1 class="text-2xl lg:text-4xl font-medium">
Preencha os dados da sua empresa
</h1>
<Contact url={Astro.request.url} client:load />
</Modal>
<Container {...Astro.props}> <Container {...Astro.props}>
<section class="space-y-5 lg:space-y-10 xl:w-4/6 mx-auto"> <section class="space-y-5 lg:space-y-10 xl:w-4/6 mx-auto">
<h1 class="text-pretty text-4xl lg:text-6xl"> <h1 class="text-pretty text-4xl lg:text-6xl">
@@ -45,7 +35,7 @@ import Modal from "~/components/Modal.astro";
</p> </p>
<button <button
data-toggle="modal" data-toggle="modal"
data-target="#planform" data-target="#solutionmodal"
data-label="EDUSEG® FLEXÍVEL" data-label="EDUSEG® FLEXÍVEL"
class="cursor-pointer font-semibold bg-lime-400 text-black hover:bg-white p-2.5 rounded-lg block text-center transition" class="cursor-pointer font-semibold bg-lime-400 text-black hover:bg-white p-2.5 rounded-lg block text-center transition"
> >
@@ -77,7 +67,7 @@ import Modal from "~/components/Modal.astro";
</p> </p>
<button <button
data-toggle="modal" data-toggle="modal"
data-target="#planform" data-target="#solutionmodal"
data-label="EDUSEG® IN-COMPANY" data-label="EDUSEG® IN-COMPANY"
class="cursor-pointer font-semibold bg-lime-400 text-black hover:bg-white p-2.5 rounded-lg block text-center transition" class="cursor-pointer font-semibold bg-lime-400 text-black hover:bg-white p-2.5 rounded-lg block text-center transition"
> >
@@ -107,7 +97,7 @@ import Modal from "~/components/Modal.astro";
</p> </p>
<button <button
data-toggle="modal" data-toggle="modal"
data-target="#planform" data-target="#solutionmodal"
data-label="EDUSEG® CONTEÚDO" data-label="EDUSEG® CONTEÚDO"
class="cursor-pointer font-semibold bg-lime-400 text-black hover:bg-white p-2.5 rounded-lg block text-center transition" class="cursor-pointer font-semibold bg-lime-400 text-black hover:bg-white p-2.5 rounded-lg block text-center transition"
> >
@@ -139,7 +129,7 @@ import Modal from "~/components/Modal.astro";
buttons.forEach((e) => { buttons.forEach((e) => {
e.addEventListener("click", (e) => { e.addEventListener("click", (e) => {
const button = e.target as HTMLButtonElement; const button = e.target as HTMLButtonElement;
// Dispatch a custom event with the selected solution label, // Dispatch a custom event with the selected solution,
// so a React component can listen to it using `window.addEventListener`. // so a React component can listen to it using `window.addEventListener`.
window.dispatchEvent( window.dispatchEvent(
new CustomEvent("custom_event:react_form", { new CustomEvent("custom_event:react_form", {

View File

@@ -56,4 +56,13 @@ import { Icon } from "astro-icon/components";
el.addEventListener("click", () => openModal(modal)); el.addEventListener("click", () => openModal(modal));
}); });
window.addEventListener("modal:open", function (event: Event) {
const customEvent = event as CustomEvent<HTMLDialogElement>;
const modal = customEvent.detail;
if (modal instanceof HTMLDialogElement) {
openModal(modal);
}
});
</script> </script>

View File

@@ -5,6 +5,8 @@ import BaseHead, {
} from "./_components/BaseHead.astro"; } from "./_components/BaseHead.astro";
import Header from "./_components/Header.astro"; import Header from "./_components/Header.astro";
import Footer from "./_components/Footer.astro"; import Footer from "./_components/Footer.astro";
import Contact from "~/components/Contact.jsx";
import Modal from "~/components/Modal.astro";
interface Props extends HeadProps {} interface Props extends HeadProps {}
--- ---
@@ -32,6 +34,7 @@ interface Props extends HeadProps {}
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag("js", new Date());
// gtag("consent", "default", { // gtag("consent", "default", {
// ad_storage: "denied", // ad_storage: "denied",
// ad_user_data: "denied", // ad_user_data: "denied",
@@ -44,6 +47,14 @@ interface Props extends HeadProps {}
</head> </head>
<body> <body>
{/* Modal */}
<Modal id="solutionmodal">
<h1 class="text-2xl lg:text-4xl font-medium">
Preencha os dados da sua empresa
</h1>
<Contact url={Astro.request.url} client:load />
</Modal>
<Header /> <Header />
<slot name="nav" /> <slot name="nav" />

View File

@@ -86,23 +86,6 @@ const currency = new Intl.NumberFormat("pt-BR", {
}, },
}); });
// window.dataLayer = window.dataLayer || [];
// function gtag(...args: any[]) {
// window.dataLayer.push(args);
// }
// gtag("event", "add_to_cart", {
// currency: "BRL",
// value: parseFloat(unit_price),
// items: [
// {
// item_id: id,
// item_name: name,
// price: parseFloat(unit_price),
// quantity: 1,
// },
// ],
// });
const r = await checkout(item); const r = await checkout(item);
const json = await r.json(); const json = await r.json();

View File

@@ -145,15 +145,36 @@ import mulhercomepi from "~/assets/mulher-com-epi.png";
<div <div
class="flex flex-col justify-center items-center border-transparent" class="flex flex-col justify-center items-center border-transparent"
> >
<a <button
href="#" data-toggle="modal"
data-target="#solutionmodal"
data-label="EDUSEG® FLEXÍVEL"
class="font-semibold bg-lime-400 text-black hover:bg-white p-2.5 px-4 rounded-lg block text-center transition" class="font-semibold bg-lime-400 text-black hover:bg-white p-2.5 px-4 rounded-lg block text-center transition"
> >
Saiba mais Saiba mais
</a> </button>
</div> </div>
</div> </div>
</section> </section>
</Container> </Container>
</div> </div>
</Layout> </Layout>
<script>
const buttons = document.querySelectorAll(
"[data-toggle=modal]",
) as NodeListOf<HTMLButtonElement>;
buttons.forEach((e) => {
e.addEventListener("click", (e) => {
const button = e.target as HTMLButtonElement;
// Dispatch a custom event with the selected solution label,
// so a React component can listen to it using `window.addEventListener`.
window.dispatchEvent(
new CustomEvent("custom_event:react_form", {
detail: button.dataset.label,
}),
);
});
});
</script>