Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added slick-carousel dependency and fixed hydration error #35

Merged
merged 5 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"react-dom": "^19.0.0",
"react-hook-form": "^7.54.2",
"react-slick": "^0.30.3",
"slick-carousel": "^1.8.1",
"sonner": "^2.0.1",
"tailwind-merge": "^3.0.2",
"tailwindcss-animate": "^1.0.7",
Expand Down
17 changes: 17 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 45 additions & 43 deletions src/app/ad-form/_components/image-ad-form.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
import React from "react";
import dynamic from "next/dynamic";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { useRouter } from "next/navigation";
import {
Select,
SelectContent,
Expand All @@ -23,7 +23,6 @@ import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import CustomMultiSelect from "@/components/ui/multi-select";
import {
demographicsOptions,
regionOptions,
Expand All @@ -32,12 +31,18 @@ import {
ageGroupOptions,
} from "@/app/constants/step-one-form-options";
import { ImageAdSchema } from "@/schemas/ad-schema";
import Image from "next/image";
import Link from "next/link";
const DynamicMultiSelect = dynamic(
() => import("@/components/ui/multi-select"),
{
ssr: false,
}
);

type FormData = z.infer<typeof ImageAdSchema>;

export const ImageAdForm = () => {
const router = useRouter();

const form = useForm<FormData>({
resolver: zodResolver(ImageAdSchema),
Expand All @@ -57,57 +62,54 @@ export const ImageAdForm = () => {
console.log("Image Ad Data:", data);
};

const handleBack = () => {
router.push("/ad-selector");
};

return (
<div className="min-h-full bg-[#F9FAFB] p-6 py-18 flex justify-center items-center">
<Card className="w-full max-w-[890px]">
<CardContent className="p-14">
<div className="mb-8">
<Button
variant="ghost"
onClick={handleBack}
<Link
href="/ad-type"
className="flex items-center text-gray-600 hover:text-gray-800 cursor-pointer p-0"
>
<img src="/arrow-left.svg" alt="Back" className="w-5 h-5 mr-2" />
<Image
src="/arrow-left.svg"
alt="Back"
className="w-5 h-5 mr-2"
width={10}
height={10}
/>
<span>Back</span>
</Button>
</Link>
</div>

<CardHeader className="p-0 mb-6 text-center">
<CardTitle className="text-2xl font-bold">
Let&apos;s set up your Ad
</CardTitle>
<p className="text-gray-500 mt-2">
Fill in the details below, then AI generates your ad instantly.
</p>
</CardHeader>
<CardTitle className="text-2xl font-bold">
Let&apos;s set up your Ad
</CardTitle>
<p className="text-gray-500 mt-2">
Fill in the details below, then AI generates your ad instantly.
</p>
</CardHeader>

<div className="mb-8">

<div className="flex justify-around items-center">

<div className="text-center">
<p className="text-sm text-black font-medium">STEP 1</p>
<p className="text-xs mt-1 text-gray-700">Set Ad goals</p>
</div>

<div className="text-center">
<p className="text-sm text-gray-400 font-medium">STEP 2</p>
<p className="text-xs mt-1 text-gray-400">Preview</p>
</div>
</div>
<div className="mb-8">
<div className="flex justify-around items-center">
<div className="text-center">
<p className="text-sm text-black font-medium">STEP 1</p>
<p className="text-xs mt-1 text-gray-700">Set Ad goals</p>
</div>

<div className="text-center">
<p className="text-sm text-gray-400 font-medium">STEP 2</p>
<p className="text-xs mt-1 text-gray-400">Preview</p>
</div>
</div>


<div className="relative w-full h-2 bg-white-200 rounded-full mt-4 mb-4">

<div className="absolute left-0 h-2 bg-[#1467C5] rounded-l-full w-[48%]"></div>

<div className="absolute right-0 h-2 bg-gray-300 rounded-r-full w-[48%]"></div>
</div>
</div>
<div className="relative w-full h-2 bg-white-200 rounded-full mt-4 mb-4">
<div className="absolute left-0 h-2 bg-[#1467C5] rounded-l-full w-[48%]"></div>

<div className="absolute right-0 h-2 bg-gray-300 rounded-r-full w-[48%]"></div>
</div>
</div>

<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
Expand Down Expand Up @@ -198,7 +200,7 @@ export const ImageAdForm = () => {
Target Age Group
</FormLabel>
<FormControl>
<CustomMultiSelect
<DynamicMultiSelect
options={ageGroupOptions}
selected={field.value || []}
onChange={field.onChange}
Expand Down Expand Up @@ -308,7 +310,7 @@ export const ImageAdForm = () => {
disabled={!form.formState.isValid}
className={`px-6 py-3 rounded-md transition-colors ${
form.formState.isValid
? "bg-[#B800B8] text-white hover:bg-[#960096]"
? "bg-[#B800B8] text-white hover:bg-[#960096] cursor-pointer"
: "bg-gray-300 text-gray-500 cursor-not-allowed"
}`}
>
Expand Down
112 changes: 93 additions & 19 deletions src/app/ad-type/ad-type-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import React, { useState } from "react";
import Image from "next/image";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";

const AdSelectorPage = () => {
const router = useRouter();
Expand All @@ -23,45 +24,118 @@ const AdSelectorPage = () => {
}
};

const handleBack = () => {
router.push("/ad-type");
};

return (
<div className="min-h-screen bg-[#F9FAFB] flex justify-center items-center p-6">
<div className="w-full max-w-lg md:max-w-3xl bg-white border rounded-md p-6 md:p-14">
<div className="mb-6">
<button
onClick={handleBack}
className="flex items-center text-gray-600 hover:text-gray-800"
<Link
href="/"
className="flex items-center text-gray-600 hover:text-gray-800 cursor-pointer p-0"
>
<img src="/arrow-left.svg" alt="Back" className="w-5 h-5 mr-2" />
<Image
src="/arrow-left.svg"
alt="Back"
className="w-5 h-5 mr-2"
width={10}
height={10}
/>
<span>Back</span>
</button>
</Link>
</div>

<h2 className="text-xl md:text-2xl font-bold mb-6">Select Ad Type</h2>

<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">

<div
className={`border p-6 rounded-lg cursor-pointer transition-all flex flex-col ${
className={`border p-6 rounded-lg cursor-pointer transition-all flex justify-between ${
selectedAdType === "image"
? "border-[#B800B8] bg-[#F3E8F3]"
: "border-gray-300 hover:border-[#B800B8]/50"
}`}
onClick={() => handleAdTypeSelect("image")}
>
<Image src="/Image.svg" alt="image svg" width={30} height={30} />
<div className="mt-4">
<h3 className="font-semibold text-base">Image Ad</h3>
<p className="text-sm text-gray-600">
Static image ads for social media, websites, and print.
</p>
<div className="flex flex-col items-start justify-center mb-4 ">
<Image
src="/image-icon.svg"
alt="image svg"
className="max-w-full max-h-full object-contain"
quality={100}
width={20}
height={20}
/>
<div className="mt-4">
<h3 className="font-semibold text-base mb-1">Image Ad</h3>
<p className="text-sm text-gray-600 max-w-[250px]">
Static image ads for social media, websites, and print
</p>
</div>
</div>

<div
className={`w-3 h-3 rounded-full border-2 flex items-center justify-center ${
selectedAdType === "image"
? "border-[#B800B8] bg-[#B800B8]"
: "border-gray-300"
}`}
>
{selectedAdType === "image" && (
<Image
src="/check.svg"
alt="image svg"
className="max-w-full max-h-full object-contain"
quality={100}
width={20}
height={20}
/>
)}
</div>
</div>
{/*
<div
className={`border-1 w-[371px] p-6 rounded-lg cursor-pointer transition-all flex items-start justify-between ${
selectedAdType === "image"
? "border-[#B800B8] bg-[#F3E8F3]"
: "border-gray-300 hover:border-[#B800B8]/50"
}`}
onClick={() => handleAdTypeSelect("image")}
>
<div className="flex flex-col items-start justify-center mb-4 ">
<Image
src="/image-icon.svg"
alt="image svg"
className="max-w-full max-h-full object-contain"
quality={100}
width={20}
height={20}
/>
<div className="mt-4">
<h3 className="font-semibold text-base mb-1">Image Ad</h3>
<p className="text-sm text-gray-600 max-w-[250px]">
Static image ads for social media, websites, and print
</p>
</div>
</div>

<div
className={`w-3 h-3 rounded-full border-2 flex items-center justify-center ${
selectedAdType === "image"
? "border-[#B800B8] bg-[#B800B8]"
: "border-gray-300"
}`}
>
{selectedAdType === "image" && (
<Image
src="/check.svg"
alt="image svg"
className="max-w-full max-h-full object-contain"
quality={100}
width={20}
height={20}
/>
)}
</div>
</div> */}


<div className="border p-6 rounded-lg flex flex-col border-gray-300 bg-gray-100 opacity-50 cursor-not-allowed">
<Image src="/video.svg" alt="Video svg" width={30} height={30} />
<div className="mt-4 flex flex-wrap items-center gap-2">
Expand All @@ -78,7 +152,7 @@ const AdSelectorPage = () => {

<div className="flex justify-end">
<button
className={`px-6 py-3 rounded-md transition-colors ${
className={`px-6 py-3 rounded-md transition-colors cursor-pointer ${
selectedAdType
? "bg-[#B800B8] text-white hover:bg-[#960096]"
: "bg-gray-300 text-gray-500 cursor-not-allowed"
Expand Down
16 changes: 2 additions & 14 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Manrope } from "next/font/google";

import { TopProgressBarProvider } from "@/lib/nprogress/top-progress-bar-provider";
import QueryProvider from "@/lib/react-query/query-provider";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";

import "./globals.css";

Expand All @@ -28,20 +30,6 @@ export default function RootLayout({
}>) {
return (
<html lang="en" className={clsx(manrope.variable)}>
<head>
<link
rel="stylesheet"
type="text/css"
charSet="UTF-8"
href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css"
/>
<link
rel="stylesheet"
type="text/css"
href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css"
/>
</head>

<body className="font-nunito bg-[#F9FAFB]">
<SonnerToaster />
<QueryProvider>
Expand Down
Loading