December 3, 2024

Dating App

Dating App

Pitch Details

1. Create the Navbar image

"use client";

import { useState, useEffect } from "react";
import Link from "next/link";
import { FaRegMoon, FaSun, FaBell, FaSearch } from "react-icons/fa";
import { IoClose } from "react-icons/io5";
import { RxHamburgerMenu } from "react-icons/rx";
import Image from "next/image";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";

const Navbar = () => {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const [isSearchDialogOpen, setIsSearchDialogOpen] = useState(false); // For Search Dialog
  const [isDarkMode, setIsDarkMode] = useState(false); // For theme toggle
  const [isMounted, setIsMounted] = useState(false); // To check if the component is mounted
  const isAuthenticated = false; // Replace with actual auth check
  const user = { name: "Ameer", profileImage: "/images/user-avatar.png" }; // Replace with actual user data

  useEffect(() => {
    setIsMounted(true);
  }, []);

  const links = [
    { name: "Explore", href: "/explore" },
    { name: "Messages", href: "/messages" },
    { name: "Preferences", href: "/preferences" },
    { name: "Profile", href: "/profile" },
    { name: "Settings", href: "/settings" },
  ];

  return (
    <>
      <nav className="bg-white dark:bg-gray-900 fixed top-0 w-full z-10 shadow-md">
        <div className="container mx-auto flex justify-between items-center px-4 py-3">
          {/* Logo */}
          <div className="text-lg font-bold text-gray-800 dark:text-white">
            <Link href="/">DatingApp</Link>
          </div>

          {/* Search Bar (Hidden on mobile) */}
          <div className="hidden md:flex w-1/3">
            <Input type="text" placeholder="Search..." className="w-full" />
          </div>

          {/* Desktop Right Section */}
          <div className="hidden md:flex items-center space-x-4">
            {links.map((link) => (
              <Link
                key={link.name}
                href={link.href}
                className="text-gray-600 dark:text-gray-300 hover:text-blue-500"
              >
                {link.name}
              </Link>
            ))}

            {/* Notifications */}
            <button
              className="text-gray-600 dark:text-gray-300 hover:text-blue-500"
              aria-label="Notifications"
            >
              <FaBell className="w-5 h-5" />
            </button>

            {/* Theme Toggle */}
            {isMounted && (
              <button
                onClick={() => setIsDarkMode(!isDarkMode)}
                className="text-gray-600 dark:text-gray-300 hover:text-blue-500"
                aria-label="Toggle Theme"
              >
                {isDarkMode ? (
                  <FaRegMoon className="w-5 h-5" />
                ) : (
                  <FaSun className="w-5 h-5" />
                )}
              </button>
            )}

            {/* Login/Logout */}
            {isMounted && isAuthenticated ? (
              <Button variant="outline">Logout</Button>
            ) : (
              <Link
                href="/auth/login"
                className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
              >
                Login
              </Link>
            )}
          </div>

          {/* Mobile Section */}
          <div className="md:hidden flex items-center space-x-4">
            {/* Search Button */}
            <button
              className="text-gray-600 dark:text-gray-300 hover:text-blue-500"
              aria-label="Search"
              onClick={() => setIsSearchDialogOpen(true)}
            >
              <FaSearch className="w-5 h-5" />
            </button>

            {/* Notifications */}
            <button
              className="text-gray-600 dark:text-gray-300 hover:text-blue-500"
              aria-label="Notifications"
            >
              <FaBell className="w-5 h-5" />
            </button>

            {/* Theme Toggle */}
            {isMounted && (
              <button
                onClick={() => setIsDarkMode(!isDarkMode)}
                className="text-gray-600 dark:text-gray-300 hover:text-blue-500"
                aria-label="Toggle Theme"
              >
                {isDarkMode ? (
                  <FaRegMoon className="w-5 h-5" />
                ) : (
                  <FaSun className="w-5 h-5" />
                )}
              </button>
            )}

            {/* Hamburger Menu */}
            <button
              onClick={() => setIsMenuOpen(!isMenuOpen)}
              className="text-gray-800 dark:text-white focus:outline-none"
            >
              {isMenuOpen ? (
                <IoClose className="w-5 h-5" />
              ) : (
                <RxHamburgerMenu className="w-5 h-5" />
              )}
            </button>
          </div>
        </div>

        {/* Mobile Dropdown Menu */}
        {isMenuOpen && (
          <div className="md:hidden bg-white dark:bg-gray-800 py-3 space-y-2">
            {links.map((link) => (
              <Link
                key={link.name}
                href={link.href}
                className="block px-4 py-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md"
                onClick={() => setIsMenuOpen(false)}
              >
                {link.name}
              </Link>
            ))}
            {!isAuthenticated && (
              <Link
                href="/auth/login"
                className="block px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
              >
                Login
              </Link>
            )}
          </div>
        )}
      </nav>

      {/* Search Dialog */}
      <Dialog open={isSearchDialogOpen} onOpenChange={setIsSearchDialogOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Search</DialogTitle>
          </DialogHeader>
          <Input type="text" placeholder="Search..." className="w-full mb-4" />
          <Button onClick={() => setIsSearchDialogOpen(false)}>Search</Button>
        </DialogContent>
      </Dialog>
    </>
  );
};

export default Navbar;

2. Create Profile Page and Its components

image

Profile Page

"use client";

import ProfileForm from "./components/ProfileForm";
import UploadAvatar from "./components/UploadAvatar";

const ProfilePage = () => {
  return (
    <div className="container mx-auto mt-8 px-4">
      {/* Page Title */}
      <h1 className="text-3xl font-bold text-gray-800 dark:text-white mb-6">
        Your Profile
      </h1>

      {/* Profile Picture and Form */}
      <div className="flex flex-col md:flex-row gap-8">
        {/* Profile Picture */}
        <div className="flex flex-col items-center">
          <UploadAvatar />
        </div>

        {/* Profile Form */}
        <div className="flex-1">
          <ProfileForm />
        </div>
      </div>
    </div>
  );
};

export default ProfilePage;

UploadAvatar Component

"use client";

import Images from "@/public/images";
import Image from "next/image";
import { useState } from "react";

const UploadAvatar = () => {
  const [image, setImage] = useState("/images/default-avatar.png");

  const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = () => {
        if (reader.result) {
          setImage(reader.result.toString());
        }
      };
      reader.readAsDataURL(file);
    }
  };

  return (
    <div className="text-center">
      <Image
        src={Images.DefaultAvatar}
        alt="Profile Avatar"
        className="w-32 h-32 rounded-full border border-gray-300 dark:border-gray-700 mb-4"
      />
      <label
        htmlFor="upload-avatar"
        className="px-4 py-2 bg-blue-500 text-white rounded-md cursor-pointer hover:bg-blue-600"
      >
        Upload Photo
      </label>
      <input
        type="file"
        id="upload-avatar"
        accept="image/*"
        className="hidden"
        onChange={handleImageUpload}
      />
    </div>
  );
};

export default UploadAvatar;

ProfileForm Component

"use client";

const ProfileForm = () => {
  return (
    <form className="space-y-4">
      {/* Name */}
      <div>
        <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
          Name
        </label>
        <input
          type="text"
          placeholder="Your Name"
          className="mt-1 block w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
        />
      </div>

      {/* Email */}
      <div>
        <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
          Email
        </label>
        <input
          type="email"
          placeholder="Your Email"
          className="mt-1 block w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
        />
      </div>

      {/* Bio */}
      <div>
        <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
          Bio
        </label>
        <textarea
          placeholder="Tell us about yourself..."
          className="mt-1 block w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
          rows={4}
        ></textarea>
      </div>

      {/* Save Changes */}
      <button
        type="submit"
        className="w-full px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
      >
        Save Changes
      </button>
    </form>
  );
};

export default ProfileForm;

3. Create preferences page and its Components Preferences Page

image

"use client";

import AgeRangeSelector from "./components/AgeRangeSelector";
import InterestsSelector from "./components/InterestsSelector";
import DistanceSlider from "./components/DistanceSlider";
import { useState } from "react";

type Preferences = {
  ageRange: [number, number];
  interests: string[];
  distance: number;
};

const PreferencesPage: React.FC = () => {
  const [preferences, setPreferences] = useState<Preferences>({
    ageRange: [18, 35],
    interests: [],
    distance: 50,
  });

  const handleSave = (): void => {
    alert("Preferences saved successfully!");
  };

  return (
    <div className="container mx-auto mt-8 px-4">
      {/* Page Title */}
      <h1 className="text-3xl font-bold text-gray-800 dark:text-white mb-6">
        Match Preferences
      </h1>

      {/* Preferences Form */}
      <div className="space-y-6">
        {/* Age Range Selector */}
        <AgeRangeSelector
          value={preferences.ageRange}
          onChange={(range: [number, number]) =>
            setPreferences({ ...preferences, ageRange: range })
          }
        />

        {/* Interests Selector */}
        <InterestsSelector
          value={preferences.interests}
          onChange={(interests: string[]) =>
            setPreferences({ ...preferences, interests })
          }
        />

        {/* Distance Slider */}
        <DistanceSlider
          value={preferences.distance}
          onChange={(distance: number) =>
            setPreferences({ ...preferences, distance })
          }
        />

        {/* Save Button */}
        <button
          onClick={handleSave}
          className="w-full px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
        >
          Save Preferences
        </button>
      </div>
    </div>
  );
};

export default PreferencesPage;

AgeRangeSelector Component

"use client";

type AgeRangeSelectorProps = {
  value: [number, number];
  onChange: (range: [number, number]) => void;
};

const AgeRangeSelector: React.FC<AgeRangeSelectorProps> = ({
  value,
  onChange,
}) => {
  const [minAge, maxAge] = value;

  return (
    <div>
      <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
        Age Range
      </label>
      <div className="flex items-center space-x-4 mt-2">
        <input
          type="number"
          min={18}
          max={100}
          value={minAge}
          onChange={(e) => onChange([Number(e.target.value), maxAge])}
          className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
        />
        <span className="text-gray-700 dark:text-gray-300">to</span>
        <input
          type="number"
          min={18}
          max={100}
          value={maxAge}
          onChange={(e) => onChange([minAge, Number(e.target.value)])}
          className="w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
        />
      </div>
    </div>
  );
};

export default AgeRangeSelector;

DistanceSlider Component

"use client";

type DistanceSliderProps = {
  value: number;
  onChange: (distance: number) => void;
};

const DistanceSlider: React.FC<DistanceSliderProps> = ({ value, onChange }) => {
  return (
    <div>
      <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
        Distance (in km)
      </label>
      <input
        type="range"
        min={1}
        max={100}
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
        className="w-full mt-2"
      />
      <p className="text-gray-700 dark:text-gray-300 mt-1">{value} km</p>
    </div>
  );
};

export default DistanceSlider;

InterestsSelector Component

"use client";

type InterestsSelectorProps = {
  value: string[];
  onChange: (interests: string[]) => void;
};

const InterestsSelector: React.FC<InterestsSelectorProps> = ({
  value,
  onChange,
}) => {
  const interestsOptions = ["Movies", "Sports", "Music", "Travel", "Fitness"];

  const toggleInterest = (interest: string) => {
    if (value.includes(interest)) {
      onChange(value.filter((i) => i !== interest));
    } else {
      onChange([...value, interest]);
    }
  };

  return (
    <div>
      <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
        Interests
      </label>
      <div className="flex flex-wrap gap-2 mt-2">
        {interestsOptions.map((interest) => (
          <button
            key={interest}
            type="button"
            onClick={() => toggleInterest(interest)}
            className={`px-4 py-2 rounded-md ${
              value.includes(interest)
                ? "bg-blue-500 text-white"
                : "bg-gray-200 text-gray-700"
            } hover:bg-blue-600`}
          >
            {interest}
          </button>
        ))}
      </div>
    </div>
  );
};

export default InterestsSelector;

4. Create Explore Page and its Components image

"use client";

import { useState } from "react";
import MatchCard from "./components/MatchCard";

type Match = {
  id: number;
  name: string;
  age: number;
  bio: string;
  image: string;
};

const ExplorePage: React.FC = () => {
  const [matches, setMatches] = useState<Match[]>([
    {
      id: 1,
      name: "Jane Doe",
      age: 27,
      bio: "Loves hiking and photography.",
      image: "/images/user1.jpg",
    },
    {
      id: 2,
      name: "John Smith",
      age: 30,
      bio: "A foodie and tech enthusiast.",
      image: "/images/user2.jpg",
    },
    {
      id: 3,
      name: "Emma Brown",
      age: 25,
      bio: "Avid reader and coffee lover.",
      image: "/images/user3.jpg",
    },
  ]);

  const handleLike = (id: number) => {
    alert(`You liked ${matches.find((match) => match.id === id)?.name}`);
  };

  const handleDislike = (id: number) => {
    alert(`You disliked ${matches.find((match) => match.id === id)?.name}`);
  };

  return (
    <div className="container mx-auto mt-8 px-4">
      <h1 className="text-3xl font-bold text-gray-800 dark:text-white mb-6">
        Explore Matches
      </h1>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        {matches.map((match) => (
          <MatchCard
            key={match.id}
            match={match}
            onLike={handleLike}
            onDislike={handleDislike}
          />
        ))}
      </div>
    </div>
  );
};

export default ExplorePage;

MatchCard Component

"use client";

type Match = {
  id: number;
  name: string;
  age: number;
  bio: string;
  image: string;
};

type MatchCardProps = {
  match: Match;
  onLike: (id: number) => void;
  onDislike: (id: number) => void;
};

const MatchCard: React.FC<MatchCardProps> = ({ match, onLike, onDislike }) => {
  return (
    <div className="bg-white dark:bg-gray-800 p-4 rounded-lg shadow-md">
      {/* Profile Image */}
      <img
        src={match.image}
        alt={match.name}
        className="w-full h-40 object-cover rounded-lg mb-4"
      />
      {/* Profile Details */}
      <h2 className="text-lg font-bold text-gray-800 dark:text-white">
        {match.name}, {match.age}
      </h2>
      <p className="text-gray-600 dark:text-gray-300 mb-4">{match.bio}</p>
      {/* Actions */}
      <div className="flex justify-between">
        <button
          onClick={() => onDislike(match.id)}
          className="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600"
        >
          Dislike
        </button>
        <button
          onClick={() => onLike(match.id)}
          className="px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600"
        >
          Like
        </button>
      </div>
    </div>
  );
};

export default MatchCard;

5. Messages Page and its Components

image

MessagesPage

"use client";

import { useState } from "react";
import ConversationList from "./components/ConversationList";
import ChatWindow from "./components/ChatWindow";

type Conversation = {
  id: number;
  name: string;
  image: string;
  lastMessage: string;
};

const MessagesPage: React.FC = () => {
  const [conversations, setConversations] = useState<Conversation[]>([
    {
      id: 1,
      name: "Jane Doe",
      image: "/images/avatars/person1.jpg",
      lastMessage: "Hi, how are you?",
    },
    {
      id: 2,
      name: "John Smith",
      image: "/images/avatars/person2.jpg",
      lastMessage: "Let’s catch up soon!",
    },
    {
      id: 3,
      name: "Emma Brown",
      image: "/images/avatars/person3.jpg",
      lastMessage: "Sounds great!",
    },
  ]);

  const [selectedConversation, setSelectedConversation] =
    useState<Conversation | null>(null);

  return (
    <div className="container mx-auto mt-8 px-4">
      <h1 className="text-3xl font-bold text-gray-800 dark:text-white mb-6">
        Messages
      </h1>
      <div className="flex flex-col md:flex-row gap-6">
        {/* Conversation List */}
        <div className="md:w-1/3">
          <ConversationList
            conversations={conversations}
            onSelect={(conversation) => setSelectedConversation(conversation)}
          />
        </div>

        {/* Chat Window */}
        <div className="md:w-2/3">
          {selectedConversation ? (
            <ChatWindow conversation={selectedConversation} />
          ) : (
            <p className="text-gray-600 dark:text-gray-300">
              Select a conversation to start chatting.
            </p>
          )}
        </div>
      </div>
    </div>
  );
};

export default MessagesPage;

ChatWindow Component

"use client";

import { useState } from "react";

type Conversation = {
  id: number;
  name: string;
  image: string;
};

type ChatWindowProps = {
  conversation: Conversation;
};

const ChatWindow: React.FC<ChatWindowProps> = ({ conversation }) => {
  const [messages, setMessages] = useState<string[]>([
    "Hi, how are you?",
    "I'm doing well, how about you?",
  ]);
  const [newMessage, setNewMessage] = useState<string>("");

  const handleSend = () => {
    if (newMessage.trim()) {
      setMessages([...messages, newMessage.trim()]);
      setNewMessage("");
    }
  };

  return (
    <div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4 flex flex-col h-full">
      {/* Header */}
      <div className="flex items-center gap-4 mb-4">
        <img
          src={conversation.image}
          alt={conversation.name}
          className="w-12 h-12 rounded-full"
        />
        <h2 className="text-xl font-bold text-gray-800 dark:text-white">
          {conversation.name}
        </h2>
      </div>

      {/* Messages */}
      <div className="flex-1 overflow-y-auto space-y-2 mb-4">
        {messages.map((message, index) => (
          <p
            key={index}
            className={`${
              index % 2 === 0
                ? "text-left text-gray-800 dark:text-white"
                : "text-right text-gray-600 dark:text-gray-300"
            }`}
          >
            {message}
          </p>
        ))}
      </div>

      {/* Input */}
      <div className="flex items-center gap-2">
        <input
          type="text"
          value={newMessage}
          onChange={(e) => setNewMessage(e.target.value)}
          className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
          placeholder="Type your message..."
        />
        <button
          onClick={handleSend}
          className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
        >
          Send
        </button>
      </div>
    </div>
  );
};

export default ChatWindow;

ConversationList Component

"use client";

type Conversation = {
  id: number;
  name: string;
  image: string;
  lastMessage: string;
};

type ConversationListProps = {
  conversations: Conversation[];
  onSelect: (conversation: Conversation) => void;
};

const ConversationList: React.FC<ConversationListProps> = ({
  conversations,
  onSelect,
}) => {
  return (
    <div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4 space-y-4">
      {conversations.map((conversation) => (
        <div
          key={conversation.id}
          onClick={() => onSelect(conversation)}
          className="flex items-center gap-4 p-2 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer rounded-lg"
        >
          <img
            src={conversation.image}
            alt={conversation.name}
            className="w-12 h-12 rounded-full"
          />
          <div>
            <h2 className="text-lg font-bold text-gray-800 dark:text-white">
              {conversation.name}
            </h2>
            <p className="text-sm text-gray-600 dark:text-gray-300">
              {conversation.lastMessage}
            </p>
          </div>
        </div>
      ))}
    </div>
  );
};

export default ConversationList;

6. Settings Page and its Components

image

Settings Page

"use client";

import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import AccountSettings from "./components/AccountSettings";
import PreferencesSettings from "./components/PreferencesSettings";
import PrivacySettings from "./components/PrivacySettings";
import { Button } from "@/components/ui/button";
import { useToast } from "@/hooks/use-toast";

const SettingsPage: React.FC = () => {
  const { toast } = useToast();
  const [settings, setSettings] = useState<{
    email: string;
    password: string;
    theme: "light" | "dark";
    notifications: boolean;
    publicProfile: boolean;
  }>({
    email: "user@example.com",
    password: "",
    theme: "light", // Initialize as "light" or "dark"
    notifications: true,
    publicProfile: true,
  });
  const [isSaving, setIsSaving] = useState(false);

  const handleSave = async (): Promise<void> => {
    setIsSaving(true);
    await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulate API call
    setIsSaving(false);

    // Trigger toast notification
    toast({
      title: "Settings Saved",
      description: "Your settings have been updated successfully.",
    });
  };

  return (
    <div className="container mx-auto mt-8 px-4">
      <h1 className="text-3xl font-bold text-center mb-8">Settings</h1>

      <Card className="space-y-6 p-6 shadow-lg">
        <CardHeader>
          <CardTitle className="text-lg font-bold">Account Settings</CardTitle>
        </CardHeader>
        <CardContent>
          <AccountSettings
            email={settings.email}
            password={settings.password}
            onChange={(updatedSettings) =>
              setSettings({ ...settings, ...updatedSettings })
            }
          />
        </CardContent>

        <CardHeader>
          <CardTitle className="text-lg font-bold">Preferences</CardTitle>
        </CardHeader>
        <CardContent>
          <PreferencesSettings
            theme={settings.theme}
            notifications={settings.notifications}
            onChange={(updatedSettings) =>
              setSettings({ ...settings, ...updatedSettings })
            }
          />
        </CardContent>

        <CardHeader>
          <CardTitle className="text-lg font-bold">Privacy Settings</CardTitle>
        </CardHeader>
        <CardContent>
          <PrivacySettings
            publicProfile={settings.publicProfile}
            onChange={(updatedSettings) =>
              setSettings({ ...settings, ...updatedSettings })
            }
          />
        </CardContent>

        <div className="text-center mt-6">
          <Button
            variant="default"
            onClick={handleSave}
            disabled={isSaving}
            className="flex items-center justify-center gap-2"
          >
            {isSaving && (
              <div className="animate-spin rounded-full h-4 w-4 border-t-2 border-b-2 border-white"></div>
            )}
            {isSaving ? "Saving..." : "Save Changes"}
          </Button>
        </div>
      </Card>
    </div>
  );
};

export default SettingsPage;

AccountSettings Component

"use client";

import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";

type AccountSettingsProps = {
  email: string;
  password: string;
  onChange: (settings: { email?: string; password?: string }) => void;
};

const AccountSettings: React.FC<AccountSettingsProps> = ({
  email,
  password,
  onChange,
}) => {
  return (
    <div className="space-y-4">
      <div>
        <Label>Email</Label>
        <Input
          type="email"
          value={email}
          onChange={(e) => onChange({ email: e.target.value })}
          placeholder="Enter your email"
        />
      </div>
      <div>
        <Label>Password</Label>
        <Input
          type="password"
          value={password}
          onChange={(e) => onChange({ password: e.target.value })}
          placeholder="Enter your password"
        />
      </div>
    </div>
  );
};

export default AccountSettings;

PreferencesSettings Component

"use client";

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";

type PreferencesSettingsProps = {
  theme: "light" | "dark";
  notifications: boolean;
  onChange: (settings: {
    theme?: "light" | "dark";
    notifications?: boolean;
  }) => void;
};

const PreferencesSettings: React.FC<PreferencesSettingsProps> = ({
  theme,
  notifications,
  onChange,
}) => {
  return (
    <div className="space-y-4">
      <div>
        <Label>Theme</Label>
        <Select
          value={theme}
          onValueChange={(value) =>
            onChange({ theme: value as "light" | "dark" })
          }
        >
          <SelectTrigger>
            <SelectValue placeholder="Select a theme" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="light">Light</SelectItem>
            <SelectItem value="dark">Dark</SelectItem>
          </SelectContent>
        </Select>
      </div>
      <div className="flex items-center space-x-2">
        <Checkbox
          checked={notifications}
          onCheckedChange={(checked) =>
            onChange({ notifications: checked as boolean })
          }
        />
        <Label>Enable Notifications</Label>
      </div>
    </div>
  );
};

export default PreferencesSettings;

PrivacySettings Component

"use client";

import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";

type PrivacySettingsProps = {
  publicProfile: boolean;
  onChange: (settings: { publicProfile?: boolean }) => void;
};

const PrivacySettings: React.FC<PrivacySettingsProps> = ({
  publicProfile,
  onChange,
}) => {
  return (
    <div className="flex items-center space-x-2">
      <Checkbox
        checked={publicProfile}
        onCheckedChange={(checked) =>
          onChange({ publicProfile: checked as boolean })
        }
      />
      <Label>Make Profile Public</Label>
    </div>
  );
};

export default PrivacySettings;

7. Update the Home Page

image

Hero Section Component

import Image from "next/image";
import { Button } from "@/components/ui/button";

export default function HeroSection() {
  return (
    <section className="relative pt-20 md:pt-24 bg-gradient-to-r from-rose-500 via-pink-400 to-red-400 text-white">
      {/* Background */}
      <Image
        src="/images/hero-bg.jpg"
        alt="Dating App Background"
        fill
        className="object-cover opacity-60"
      />

      {/* Content */}
      <div className="relative z-10 flex flex-col items-center justify-center h-[calc(100vh-5rem)] space-y-8 text-center px-4">
        <h1 className="text-5xl font-extrabold drop-shadow-md">
          Discover <span className="text-yellow-300">Your Love</span> Today
        </h1>
        <p className="text-xl max-w-2xl drop-shadow-sm">
          Join a vibrant community of singles and build meaningful connections.
        </p>
        <Button className="bg-yellow-300 text-red-800 px-6 py-3 rounded-lg font-bold hover:bg-yellow-400 transition">
          Get Started
        </Button>
      </div>
    </section>
  );
}

FeaturesSection Component

import { FaHeart, FaLock, FaMagic } from "react-icons/fa";

export default function FeaturesSection() {
  const features = [
    {
      icon: <FaHeart className="text-pink-500 w-10 h-10" />,
      title: "Smart Matchmaking",
      description: "Our algorithm finds your most compatible matches.",
    },
    {
      icon: <FaLock className="text-blue-500 w-10 h-10" />,
      title: "Privacy First",
      description: "We prioritize your safety and keep your data secure.",
    },
    {
      icon: <FaMagic className="text-yellow-500 w-10 h-10" />,
      title: "Easy to Use",
      description: "A user-friendly experience designed for everyone.",
    },
  ];

  return (
    <section className="bg-white py-16 text-gray-800">
      <div className="container mx-auto text-center">
        <h2 className="text-3xl font-extrabold mb-8">Why Choose Us?</h2>
        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
          {features.map((feature, index) => (
            <div key={index} className="flex flex-col items-center space-y-4">
              {feature.icon}
              <h3 className="text-xl font-bold">{feature.title}</h3>
              <p className="text-gray-600">{feature.description}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

TestimonialsSection Component

export default function TestimonialsSection() {
  const testimonials = [
    {
      name: "Sophia",
      message: "This app completely changed my life! I found my soulmate here.",
      image: "/images/avatars/person1.jpg",
    },
    {
      name: "Liam",
      message: "Amazing experience! The matchmaking system is so accurate.",
      image: "/images/avatars/person2.jpg",
    },
    {
      name: "Emma",
      message: "I love how secure and easy to use this app is.",
      image: "/images/avatars/person3.jpg",
    },
  ];

  return (
    <section className="bg-gray-100 py-16">
      <div className="container mx-auto text-center">
        <h2 className="text-3xl font-extrabold mb-8">What Our Users Say</h2>
        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
          {testimonials.map((testimonial, index) => (
            <div
              key={index}
              className="bg-white rounded-lg p-6 shadow-lg text-center"
            >
              <img
                src={testimonial.image}
                alt={testimonial.name}
                className="w-20 h-20 rounded-full mx-auto mb-4"
              />
              <p className="text-gray-600 italic mb-4">
                "{testimonial.message}"
              </p>
              <h4 className="text-lg font-bold">{testimonial.name}</h4>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

StatsSection Component

export default function StatsSection() {
  const stats = [
    { value: "5M+", label: "Happy Users" },
    { value: "10M+", label: "Matches Made" },
    { value: "50+", label: "Countries Served" },
  ];

  return (
    <section className="bg-gradient-to-r from-pink-500 to-red-500 text-white py-16">
      <div className="container mx-auto text-center">
        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
          {stats.map((stat, index) => (
            <div key={index} className="space-y-2">
              <h3 className="text-4xl font-extrabold">{stat.value}</h3>
              <p className="text-lg">{stat.label}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

CallToAction Component

import { Button } from "@/components/ui/button";

export default function CallToAction() {
  return (
    <section className="bg-yellow-300 py-16 text-center">
      <h2 className="text-3xl font-extrabold mb-4 text-pink-700">
        Ready to Find Love?
      </h2>
      <p className="text-gray-800 mb-8">
        Join now and start your journey towards a meaningful connection.
      </p>
      <Button className="bg-pink-500 text-white px-8 py-3 rounded-lg hover:bg-pink-600">
        Get Started
      </Button>
    </section>
  );
}