"use client"; import React, { useRef, useState, useEffect, useLayoutEffect } from "react"; import { Upload } from "antd"; import { Col, Row } from "antd/lib/grid"; import "../css/App.scss" import "../css/base/spacing.scss" import "../css/base/modal.scss" import "../css/base/tabs.scss" import "../css/base/text.scss" import "../css/base/display.scss" import "../css/base/form.scss" import "../css/base/button.scss" import "../css/onboardingFlow.scss" import "../css/LinkEditorModal.scss"; import "../css/ProductEditorModal.scss"; import "../css/ModuleOndemandVideo.scss"; import "../css/ModuleShopify.scss" import Tabs from "antd/lib/tabs"; import Button from "antd/lib/button"; import Alert from "antd/lib/alert"; import * as yup from "yup"; import classNames from "classnames"; import { Field, Form, Formik, FormikProps } from "formik"; import Modal from "@/components/Modal/Modal"; // Adjust this path as needed import { Text } from "@/components/Typography/Text"; import ImageUpload from "@/components/ImageUpload/ImageUpload"; import { AntInput, FieldType } from "@/components/Form/FormItem"; import { LinkItem } from "@/models/talent/talent-profile-module.model"; //import icon import InfoIcon from "@/icons/Infoicon"; import CloseOutlineIcon from "@/icons/Closeoutlineicon"; const initialProductValues: LinkItem = { title: "", url: "", order: 0, visible: true, }; const initialSpecialOfferValues: LinkItem = { title: "", url: "", order: 0, specialOffer: { thumbnail: "", title: "", storeUrl: "", couponCode: "", }, visible: true, }; const LINK_TYPES = { NORMAL: "NORMAL", SPECIAL_OFFER: "SPECIAL_OFFER", }; const Icon = ({ className, name, width, height }: { className?: string; name: string; width?: number; height?: number }) => { return ( [icon: {name}] ); }; const dummyPhoto = { url: "https://via.placeholder.com/369", // static test image fileName: "placeholder.jpg", loading: false, }; const onUploadSuccess = (file: any) => { console.log("Upload success:", file); }; const onRemove = (file: any) => { console.log("Removed:", file); }; const validateLinkSchema = yup.object().shape({ title: yup.string().required("Please enter the link title"), url: yup .string() .required("Please enter the URL") .url("Please enter a valid URL"), }); const validateSpecialOfferSchema = yup.object().shape({ specialOffer: yup.object().shape({ title: yup .string() .required("Please add the offer information") .test("len", "Offer not more than 50 characters", (val) => { if (val == undefined) { return true; } return val.length == 0 || (val.length >= 1 && val.length <= 50); }), storeUrl: yup .string() .required("Please enter the URL") .url("Please enter a valid URL"), }), }); export type LinkEditorModalFormValues = Pick< LinkItem, "thumbnail" | "url" | "title" | "specialOffer" | "order" | "visible" >; export default function Page() { const [isModalOpen, setIsModalOpen] = useState(false); // Dummy state vars to eliminate TS errors const [linkType, setLinkType] = useState(LINK_TYPES.NORMAL); const [isEdit, setIsEdit] = useState(false); const [showAlert, setShowAlert] = useState(true); const [initialValues, setInitialValues] = useState(); function handleSubmit(values: LinkEditorModalFormValues, formikHelpers: FormikHelpers): void | Promise { throw new Error("Function not implemented."); } const dummyOptions = [ { label: "Option A", value: "A" }, { label: "Option B", value: "B" }, ]; const [modalTop, setModalTop] = useState(); // default safe gap const modalRef = useRef(null); let newTop: number; //CUSTOM LOGIC: HANDLE THE TOP OF THE MODAL OF DIFFERENT PLATFORMS useEffect(() => { const updateModalTop = () => { const modalEl = document.querySelector('.link-editor-modal') as HTMLElement; if (!modalEl) return; const modalHeight = modalEl.getBoundingClientRect().height; const windowHeight = window.innerHeight; const isMobile = window.innerWidth <= 768; //PLATFORM LOGIC if(!isMobile) { if (modalHeight + 60 > windowHeight) { newTop = 20; setModalTop(newTop); //console.log('DESKTOP OVERFLOW'); } else { //newTop = Math.max((windowHeight - modalHeight) / 4, 30); newTop = 20; setModalTop(newTop); //console.log('DESKTOP CENTERED'); } } else { if (modalHeight + 60 > windowHeight) { newTop = 20; setModalTop(newTop); //console.log('MOBILE OVERFLOW'); } else { //newTop = 20; //setModalTop(newTop); newTop = Math.max( (windowHeight / 2) - (2.4 * modalHeight), 30); setModalTop(newTop); //modalEl.style.removeProperty('top'); //console.log('MOBILE CENTERED'); } } modalEl.style.top = `${newTop}px`; // 🔥 Direct DOM update }; if (isModalOpen) { setTimeout(updateModalTop, 100); // Wait for DOM to fully render window.addEventListener("resize", updateModalTop); } return () => { window.removeEventListener("resize", updateModalTop); }; }, [isModalOpen, linkType]); useLayoutEffect(() => { const adjustMargin = () => { if (!isModalOpen) return; if (linkType === LINK_TYPES.SPECIAL_OFFER) { //console.log('SPECIAL') const form = document.querySelector(".offer-form-item") as HTMLElement; const inputBox = form.getElementsByClassName('ant-form-item-has-success')[0] as HTMLElement; const hasError = form.querySelector(".ant-form-item-explain-error") as HTMLElement; if (inputBox) { inputBox.style.marginBottom = hasError ? "24px" : "0px"; } } if (linkType === LINK_TYPES.NORMAL) { //console.log('NORMAL') const form = document.querySelector(".link-editor-form") as HTMLElement; const inputBoxes = form?.getElementsByClassName("ant-form-item-has-success"); const inputBox = inputBoxes?.[1] as HTMLElement; if (inputBox) { inputBox.style.marginBottom = "24px"; } } }; // Delay just until after DOM mounts, but before paint requestAnimationFrame(() => { adjustMargin(); }); }, [linkType, isModalOpen]); //DEALING WITH ERROR LABELS const [errorActivated, setErrorActivated] = useState(false); useEffect(() => { if (!isModalOpen) return; const formRoot = document.querySelector(".offer-form-item"); if (!formRoot) return; const observer = new MutationObserver(() => { const errorLabels = formRoot.querySelectorAll(".ant-form-item-explain-error"); // ✅ You can react to the presence of ANY error if (errorLabels.length > 0) { //console.log("🚨 Error label activated"); // Optional: do something here setErrorActivated(true) } else { console.log("✅ No errors"); } }); observer.observe(formRoot, { childList: true, subtree: true, }); return () => observer.disconnect(); }, [isModalOpen, linkType]); //TRIGGER FOR ACTIVATED ERROR useEffect(() => { if(errorActivated) { console.log('ERROR ACTIVATED'); const form = document.querySelector(".offer-form-item") as HTMLElement; const inputBox = form.getElementsByClassName('ant-form-item')[0] as HTMLElement; if (inputBox) { inputBox.style.marginBottom = "24px"; } } }, [errorActivated]); return ( <> {/** INLINE ROOT STYLING */} 1: Home setIsModalOpen(true)}>Open Modal setIsModalOpen(false)} maskClosable={false} ref={modalRef} > setLinkType(activeKey)} activeKey={linkType} className={isEdit ? "is-edit" : ""} > {!isEdit && ( Link} key={LINK_TYPES.NORMAL} /> )} {!isEdit && ( Special offers} key={LINK_TYPES.SPECIAL_OFFER} > {showAlert && ( } showIcon closeText={ } onClose={() => { setShowAlert(false); localStorage.setItem( "CLOSE_ALERT_ADD_SPECIAL_OFFER", "true" ); }} /> )} )} {/* IMAGE UPLOAD BUTTON */} Thumbnail Photo {/* //TODO */} Use a size that’s at least 369 x 369 pixels and 6MB or less <> {linkType === LINK_TYPES.NORMAL ? ( <> > ) : ( <> {`0/50 characters`} > )} Cancel Done > > ); }
1: Home