enhance Feedback component with referer tracking
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# NEXT_PUBLIC_API=http://192.168.1.250:3003/
|
||||
# NEXT_PUBLIC_API=http://192.168.1.224:3003/
|
||||
NEXT_PUBLIC_API=https://graff.estate/api/
|
||||
NEXT_PUBLIC_S3_BUCKET=https://storage.yandexcloud.net/dult-faib-knac-fint/
|
||||
NEXT_PUBLIC_TINYMCE_API_KEY=2vf68779upg45y46o6g5gaxldy9gzr399eyaaqa0ki3mj2h2
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client";
|
||||
|
||||
import { api } from "@/api";
|
||||
import { projectsTags } from "@/consts/projectsTags";
|
||||
import { Product } from "@/types/Product";
|
||||
@@ -9,15 +8,19 @@ import { getExampleNumber } from "libphonenumber-js";
|
||||
import examples from "libphonenumber-js/mobile/examples";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { ChangeEvent, useMemo, useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import ReactInputMask from "react-input-mask";
|
||||
import { Country } from "react-phone-number-input";
|
||||
import CheckIcon from "../../../public/icons/check.svg";
|
||||
import useAddReferer from "@/hooks/useAddReferer";
|
||||
import { useRefererStore } from "@/stores/useRefererStore";
|
||||
|
||||
export function Feedback() {
|
||||
const pathname = usePathname();
|
||||
|
||||
useAddReferer();
|
||||
|
||||
return (
|
||||
<div
|
||||
id="contacts"
|
||||
@@ -40,6 +43,7 @@ interface IInput {
|
||||
phone: string;
|
||||
email: string;
|
||||
products: Product[];
|
||||
referer?: string | null;
|
||||
}
|
||||
|
||||
export function FeedbackForm() {
|
||||
@@ -47,6 +51,8 @@ export function FeedbackForm() {
|
||||
[string, Country]
|
||||
>(["+7", "RU"]);
|
||||
|
||||
const { referer } = useRefererStore();
|
||||
|
||||
const placeholder = useMemo(
|
||||
() =>
|
||||
getExampleNumber(country, examples)
|
||||
@@ -64,7 +70,7 @@ export function FeedbackForm() {
|
||||
const { register, handleSubmit, formState } = form;
|
||||
|
||||
async function onSubmit(data: IInput) {
|
||||
await api.post("mail", { json: data }).json();
|
||||
await api.post("mail", { json: { ...data, referer } }).json();
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -77,7 +83,7 @@ export function FeedbackForm() {
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
<div className="lg:space-y-[1.111vw] space-y-4">
|
||||
<p className="font-medium heading2">Нам нужно</p>
|
||||
<p className="heading2 font-medium">Нам нужно</p>
|
||||
<CheckboxesGroup name="products" options={projectsTags} />
|
||||
</div>
|
||||
<input
|
||||
@@ -126,7 +132,7 @@ export function FeedbackForm() {
|
||||
maskChar={null}
|
||||
mask={"+7 " + (placeholder?.replace(/\d/g, "9") ?? "")}
|
||||
placeholder={"+7 " + placeholder}
|
||||
className="w-full h-full bg-transparent rounded-none transition-all outline-none placeholder:btnl placeholder:font-medium placeholder:select-none peer btnl"
|
||||
className="placeholder:btnl placeholder:font-medium placeholder:select-none peer btnl w-full h-full bg-transparent rounded-none transition-all outline-none"
|
||||
/>
|
||||
<div className="bottom-0 absolute w-full border-b border-[#37393B] peer-focus:border-white -mb-2" />
|
||||
</div>
|
||||
@@ -155,10 +161,10 @@ export function FeedbackForm() {
|
||||
) : (
|
||||
<div className="bg-[#37393B99] aspect-[643/480] w-full rounded-2xl flex justify-center items-center">
|
||||
<div className="flex gap-3 justify-center items-center">
|
||||
<div className="p-3 rounded-full bg-gradient">
|
||||
<div className="bg-gradient p-3 rounded-full">
|
||||
<CheckIcon className="text-white lg:w-[1.667vw] lg:h-[1.667vw] w-6 h-6" />
|
||||
</div>
|
||||
<p className="font-medium heading2">
|
||||
<p className="heading2 font-medium">
|
||||
Мы получили заявку
|
||||
<br />и скоро свяжемся с вами!
|
||||
</p>
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import Link from 'next/link';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import ArrowMoreIcon from '../../../public/icons/arrow_more.svg';
|
||||
import RutubeIcon from '../../../public/icons/rutube.svg';
|
||||
import TelegramIcon from '../../../public/icons/tg.svg';
|
||||
import VkIcon from '../../../public/icons/vk.svg';
|
||||
import YoutubeIcon from '../../../public/icons/youtube.svg';
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
"use client";
|
||||
import Link from "next/link";
|
||||
import { PropsWithChildren, useEffect } from "react";
|
||||
import ArrowMoreIcon from "../../../public/icons/arrow_more.svg";
|
||||
import RutubeIcon from "../../../public/icons/rutube.svg";
|
||||
import TelegramIcon from "../../../public/icons/tg.svg";
|
||||
import VkIcon from "../../../public/icons/vk.svg";
|
||||
import YoutubeIcon from "../../../public/icons/youtube.svg";
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="lg:px-5 lg:pb-5 md:max-lg:px-4 md:max-lg:pb-4 px-[10px] pb-[10px] space-y-6 mb-0">
|
||||
<div className="max-md:flex-col lg:gap-[0.833vw] md:max-lg:gap-[1.042vw] flex gap-[1.111vw]">
|
||||
<Link
|
||||
href={'tel:' + '8 800 770 00 67'.replaceAll(' ', '')}
|
||||
href={"tel:" + "8 800 770 00 67".replaceAll(" ", "")}
|
||||
className="lg:p-[1.667vw] p-6 flex flex-col justify-between max-md:gap-y-10 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] lg:rounded-[1.111vw] rounded-2xl lg:aspect-[696/248] lg:w-[48.333vw] md:max-lg:w-[47.656vw] hover:bg-[#37393B99] bg-transparent transition-colors"
|
||||
>
|
||||
<p className="text-[#7A7A7A] text1 font-medium">Позвонить</p>
|
||||
@@ -21,7 +23,7 @@ export function Footer() {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href={'mailto:' + 'info@graff.tech'}
|
||||
href={"mailto:" + "info@graff.tech"}
|
||||
className="lg:p-[1.667vw] p-6 flex flex-col justify-between max-md:gap-y-10 bg-[linear-gradient(to_top_left,#7A7A7A50,transparent)] lg:rounded-[1.111vw] rounded-2xl lg:aspect-[624/248] lg:w-[43.333vw] md:max-lg:w-[47.656vw] hover:bg-[#37393B99] bg-transparent transition-colors"
|
||||
>
|
||||
<p className="text-[#7A7A7A] text1 font-medium">Написать</p>
|
||||
@@ -47,7 +49,7 @@ export function Footer() {
|
||||
</div>
|
||||
<div className="lg:gap-x-[1.667vw] gap-y-2 lg:flex grid">
|
||||
<Link
|
||||
href={'/policy'}
|
||||
href={"/policy"}
|
||||
className="text-[#37393B] text1 font-medium leading-[18.9px] w-fit"
|
||||
>
|
||||
Политика конфиденциальности и обработки персональных данных
|
||||
@@ -56,7 +58,7 @@ export function Footer() {
|
||||
© 2025 GRAFF interactive. Все права защищены
|
||||
</p>
|
||||
<Link
|
||||
href={'https://graff.tech'}
|
||||
href={"https://graff.tech"}
|
||||
className="text-[#37393B] text1 font-medium leading-[18.9px] lg:w-fit md:col-start-2 md:text-right w-full"
|
||||
>
|
||||
graff.tech
|
||||
@@ -69,7 +71,7 @@ export function Footer() {
|
||||
export function ContactLink({
|
||||
children,
|
||||
href,
|
||||
className = '',
|
||||
className = "",
|
||||
}: PropsWithChildren<{ href: string; className?: string }>) {
|
||||
return (
|
||||
<Link
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useRefererStore } from "@/stores/useRefererStore";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function useAddReferer() {
|
||||
const { setReferer } = useRefererStore();
|
||||
|
||||
useEffect(() => {
|
||||
const referer = new URLSearchParams(window.location.search).get("ref");
|
||||
|
||||
if (!referer) return;
|
||||
setReferer(referer);
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default useAddReferer;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
|
||||
export const useRefererStore = create<{
|
||||
referer: string | null;
|
||||
setReferer: (referer: string | null) => void;
|
||||
}>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
referer: null,
|
||||
setReferer: (referer) => set({ referer }),
|
||||
}),
|
||||
{
|
||||
name: "referer",
|
||||
}
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user