From 02f2398c40af734f3ae8f5ecf105a02cbb0330cb Mon Sep 17 00:00:00 2001 From: teetangh Date: Thu, 12 Dec 2024 05:03:14 +0530 Subject: [PATCH] tallied both render calendar and pricing toggle --- .../{ => components}/ClassesAndWebinars.tsx | 7 +- .../ConsultantSkeletonLoader.tsx | 2 +- .../{ => components}/CustomAvailability.tsx | 0 .../{ => components}/PricingToggle.tsx | 9 +- .../{ => components}/Review.tsx | 0 .../{ => components}/WeeklyAvailability.tsx | 16 ++- app/explore/experts/[consultantId]/page.tsx | 134 +++++++++++------- types/slots.ts | 3 + 8 files changed, 104 insertions(+), 67 deletions(-) rename app/explore/experts/[consultantId]/{ => components}/ClassesAndWebinars.tsx (94%) rename app/explore/experts/[consultantId]/{ => components}/ConsultantSkeletonLoader.tsx (97%) rename app/explore/experts/[consultantId]/{ => components}/CustomAvailability.tsx (100%) rename app/explore/experts/[consultantId]/{ => components}/PricingToggle.tsx (99%) rename app/explore/experts/[consultantId]/{ => components}/Review.tsx (100%) rename app/explore/experts/[consultantId]/{ => components}/WeeklyAvailability.tsx (89%) diff --git a/app/explore/experts/[consultantId]/ClassesAndWebinars.tsx b/app/explore/experts/[consultantId]/components/ClassesAndWebinars.tsx similarity index 94% rename from app/explore/experts/[consultantId]/ClassesAndWebinars.tsx rename to app/explore/experts/[consultantId]/components/ClassesAndWebinars.tsx index 3ebd4fc..c9358db 100644 --- a/app/explore/experts/[consultantId]/ClassesAndWebinars.tsx +++ b/app/explore/experts/[consultantId]/components/ClassesAndWebinars.tsx @@ -1,9 +1,8 @@ -import React, { useEffect, useState } from "react"; -import { useToast } from "@/components/ui/use-toast"; -import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { ClassPlan, WebinarPlan } from "@prisma/client"; import { CalendarIcon, ClockIcon } from "lucide-react"; -import { Class, Webinar, ClassPlan, WebinarPlan } from "@prisma/client"; +import React from "react"; interface ClassesAndWebinarsProps { classPlans: ClassPlan[]; diff --git a/app/explore/experts/[consultantId]/ConsultantSkeletonLoader.tsx b/app/explore/experts/[consultantId]/components/ConsultantSkeletonLoader.tsx similarity index 97% rename from app/explore/experts/[consultantId]/ConsultantSkeletonLoader.tsx rename to app/explore/experts/[consultantId]/components/ConsultantSkeletonLoader.tsx index cd4ab0c..0e13087 100644 --- a/app/explore/experts/[consultantId]/ConsultantSkeletonLoader.tsx +++ b/app/explore/experts/[consultantId]/components/ConsultantSkeletonLoader.tsx @@ -11,7 +11,7 @@ export const ConsultantSkeletonLoader: React.FC = () => { let dotIndex = 0; const interval = setInterval(() => { - setLoadingText((prevText) => { + setLoadingText(() => { const baseText = "Please wait while we are fetching consultant details"; return `${baseText}${dots[dotIndex]}`; }); diff --git a/app/explore/experts/[consultantId]/CustomAvailability.tsx b/app/explore/experts/[consultantId]/components/CustomAvailability.tsx similarity index 100% rename from app/explore/experts/[consultantId]/CustomAvailability.tsx rename to app/explore/experts/[consultantId]/components/CustomAvailability.tsx diff --git a/app/explore/experts/[consultantId]/PricingToggle.tsx b/app/explore/experts/[consultantId]/components/PricingToggle.tsx similarity index 99% rename from app/explore/experts/[consultantId]/PricingToggle.tsx rename to app/explore/experts/[consultantId]/components/PricingToggle.tsx index 32f323e..c76751d 100644 --- a/app/explore/experts/[consultantId]/PricingToggle.tsx +++ b/app/explore/experts/[consultantId]/components/PricingToggle.tsx @@ -11,17 +11,16 @@ import { Dialog, DialogContent, DialogDescription, - DialogFooter, DialogHeader, DialogTitle, - DialogTrigger, + DialogTrigger } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { motion } from "framer-motion"; -import { ClockIcon, X } from "lucide-react"; +import { ClockIcon } from "lucide-react"; import { useSession } from "next-auth/react"; -import { useState, useMemo } from "react"; -import { PricingOption, defaultConsultationOptions, defaultSubscriptionOptions } from "./defaults"; +import { useMemo, useState } from "react"; +import { PricingOption, defaultConsultationOptions, defaultSubscriptionOptions } from "../defaults"; interface PricingToggleProps { consultationOptions?: PricingOption[]; diff --git a/app/explore/experts/[consultantId]/Review.tsx b/app/explore/experts/[consultantId]/components/Review.tsx similarity index 100% rename from app/explore/experts/[consultantId]/Review.tsx rename to app/explore/experts/[consultantId]/components/Review.tsx diff --git a/app/explore/experts/[consultantId]/WeeklyAvailability.tsx b/app/explore/experts/[consultantId]/components/WeeklyAvailability.tsx similarity index 89% rename from app/explore/experts/[consultantId]/WeeklyAvailability.tsx rename to app/explore/experts/[consultantId]/components/WeeklyAvailability.tsx index 8742611..8e431a1 100644 --- a/app/explore/experts/[consultantId]/WeeklyAvailability.tsx +++ b/app/explore/experts/[consultantId]/components/WeeklyAvailability.tsx @@ -15,14 +15,18 @@ interface WeeklyAvailabilityProps { selectedSlotId?: string; } +function convertUTCToLocal(date: Date): Date { + const offset = date.getTimezoneOffset(); + return new Date(date.getTime() - (offset * 60 * 1000)); +} + const formatTime = (isoString: string): string => { try { - // Extract hours and minutes from the ISO string - const date = new Date(isoString); - if (isNaN(date.getTime())) { - throw new Error("Invalid date"); - } - return date.toLocaleTimeString([], { + // Convert UTC time to local time + const utcDate = new Date(isoString); + const localDate = convertUTCToLocal(utcDate); + + return localDate.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: true, diff --git a/app/explore/experts/[consultantId]/page.tsx b/app/explore/experts/[consultantId]/page.tsx index 23b7a54..5481e63 100644 --- a/app/explore/experts/[consultantId]/page.tsx +++ b/app/explore/experts/[consultantId]/page.tsx @@ -14,6 +14,7 @@ import { TSlotTiming } from "@/types/slots"; import { ConsultantReview, ConsultationPlan, + DayOfWeek, SubscriptionPlan, User, } from "@prisma/client"; @@ -21,12 +22,12 @@ import { StarIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { use, useCallback, useEffect, useMemo, useState } from "react"; -import { ClassesAndWebinars } from "./ClassesAndWebinars"; -import { ConsultantSkeletonLoader } from "./ConsultantSkeletonLoader"; -import { CustomAvailability } from "./CustomAvailability"; -import PricingToggle from "./PricingToggle"; -import Review from "./Review"; -import { WeeklyAvailability } from "./WeeklyAvailability"; +import { ClassesAndWebinars } from "./components/ClassesAndWebinars"; +import { ConsultantSkeletonLoader } from "./components/ConsultantSkeletonLoader"; +import { CustomAvailability } from "./components/CustomAvailability"; +import PricingToggle from "./components/PricingToggle"; +import Review from "./components/Review"; +import { WeeklyAvailability } from "./components/WeeklyAvailability"; interface PricingOption { title: string; @@ -39,6 +40,21 @@ interface PricingOption { type Params = Promise<{ consultantId: string }>; type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>; +const dayMap: Record = { + 0: DayOfWeek.SUNDAY, + 1: DayOfWeek.MONDAY, + 2: DayOfWeek.TUESDAY, + 3: DayOfWeek.WEDNESDAY, + 4: DayOfWeek.THURSDAY, + 5: DayOfWeek.FRIDAY, + 6: DayOfWeek.SATURDAY +}; + +function convertUTCToLocal(date: Date): Date { + const offset = date.getTimezoneOffset(); + return new Date(date.getTime() - (offset * 60 * 1000)); +} + export default function ExpertProfile( props: Readonly<{ params: Params; @@ -69,7 +85,6 @@ export default function ExpertProfile( params.consultantId, ); setConsultantDetails(consultantData); - console.log(consultantData); if (consultantData.userId) { const userData = await fetchUserDetails(consultantData.userId); setUserDetails(userData); @@ -103,28 +118,51 @@ export default function ExpertProfile( // For weekly schedule, use the slots directly from consultantDetails const weeklySlots = consultantDetails.slotsOfAvailabilityWeekly.map( (slot) => { - // Extract time from the ISO string and ensure it's a string - const startTimeStr = - typeof slot.slotStartTimeInUTC === "string" - ? slot.slotStartTimeInUTC - : new Date(slot.slotStartTimeInUTC).toISOString(); - const endTimeStr = - typeof slot.slotEndTimeInUTC === "string" - ? slot.slotEndTimeInUTC - : new Date(slot.slotEndTimeInUTC).toISOString(); + // Get the selected date's day + const selectedDay = dayMap[selectedDate.getDay()]; + + // Only map slots for the selected day + if (slot.dayOfWeekforStartTimeInUTC !== selectedDay) { + return null; + } + + // Create a new date object for the selected date + const slotDate = new Date(selectedDate); + + // Parse hours and minutes from the UTC time + const startTime = new Date(slot.slotStartTimeInUTC); + const endTime = new Date(slot.slotEndTimeInUTC); + + // Convert UTC times to local times + const localStartTime = convertUTCToLocal(startTime); + const localEndTime = convertUTCToLocal(endTime); + + // Set the hours and minutes on the selected date + const startDateTime = new Date(slotDate); + startDateTime.setHours(localStartTime.getHours(), localStartTime.getMinutes(), 0, 0); + + const endDateTime = new Date(slotDate); + endDateTime.setHours(localEndTime.getHours(), localEndTime.getMinutes(), 0, 0); + + // If the slot crosses midnight, adjust the end date + if (endDateTime < startDateTime) { + endDateTime.setDate(endDateTime.getDate() + 1); + } return { slotId: slot.id, dateInISO: selectedDate.toISOString(), - slotStartTimeInUTC: startTimeStr, - slotEndTimeInUTC: endTimeStr, + dayOfWeek: slot.dayOfWeekforStartTimeInUTC, + slotStartTimeInUTC: startDateTime.toISOString(), + slotEndTimeInUTC: endDateTime.toISOString(), slotOfAvailabilityId: slot.id, slotOfAppointmentId: "", - localStartTime: startTimeStr, - localEndTime: endTimeStr, + localStartTime: startDateTime.toLocaleTimeString(), + localEndTime: endDateTime.toLocaleTimeString(), }; }, - ); + ).filter((slot): slot is TSlotTiming => slot !== null); + setSlotTimings(weeklySlots); } else if (consultantDetails.scheduleType === "CUSTOM") { // For custom schedule, use the custom slots from consultantDetails @@ -137,28 +175,23 @@ export default function ExpertProfile( ); return slotDate.toDateString() === selectedDate.toDateString(); }) - .map((slot) => ({ - slotId: slot.id, - dateInISO: selectedDate.toISOString(), - slotStartTimeInUTC: - typeof slot.slotStartTimeInUTC === "string" - ? slot.slotStartTimeInUTC - : new Date(slot.slotStartTimeInUTC).toISOString(), - slotEndTimeInUTC: - typeof slot.slotEndTimeInUTC === "string" - ? slot.slotEndTimeInUTC - : new Date(slot.slotEndTimeInUTC).toISOString(), - slotOfAvailabilityId: slot.id, - slotOfAppointmentId: "", - localStartTime: - typeof slot.slotStartTimeInUTC === "string" - ? slot.slotStartTimeInUTC - : new Date(slot.slotStartTimeInUTC).toISOString(), - localEndTime: - typeof slot.slotEndTimeInUTC === "string" - ? slot.slotEndTimeInUTC - : new Date(slot.slotEndTimeInUTC).toISOString(), - })); + .map((slot) => { + const startDateTime = convertUTCToLocal(new Date(slot.slotStartTimeInUTC)); + const endDateTime = convertUTCToLocal(new Date(slot.slotEndTimeInUTC)); + + return { + slotId: slot.id, + dateInISO: selectedDate.toISOString(), + dayOfWeek: dayMap[startDateTime.getDay()], + slotStartTimeInUTC: startDateTime.toISOString(), + slotEndTimeInUTC: endDateTime.toISOString(), + slotOfAvailabilityId: slot.id, + slotOfAppointmentId: "", + localStartTime: startDateTime.toLocaleTimeString(), + localEndTime: endDateTime.toLocaleTimeString(), + }; + }); + setSlotTimings(customSlots); } } @@ -264,16 +297,13 @@ export default function ExpertProfile( setSelectedSlot({ slotId: slot.id, dateInISO: new Date().toISOString(), + dayOfWeek: slot.dayOfWeekforStartTimeInUTC, slotStartTimeInUTC: slot.slotStartTimeInUTC, slotEndTimeInUTC: slot.slotEndTimeInUTC, slotOfAvailabilityId: slot.id, slotOfAppointmentId: "", - localStartTime: new Date( - `1970-01-01T${slot.slotStartTimeInUTC}`, - ).toISOString(), - localEndTime: new Date( - `1970-01-01T${slot.slotEndTimeInUTC}`, - ).toISOString(), + localStartTime: new Date(slot.slotStartTimeInUTC).toLocaleTimeString(), + localEndTime: new Date(slot.slotEndTimeInUTC).toLocaleTimeString(), }) } selectedSlotId={selectedSlot?.slotId} @@ -302,12 +332,13 @@ export default function ExpertProfile( setSelectedSlot({ slotId: slot.id, dateInISO: new Date(slot.slotStartTimeInUTC).toISOString(), + dayOfWeek: dayMap[new Date(slot.slotStartTimeInUTC).getDay()], slotStartTimeInUTC: slot.slotStartTimeInUTC, slotEndTimeInUTC: slot.slotEndTimeInUTC, slotOfAvailabilityId: slot.id, slotOfAppointmentId: "", - localStartTime: new Date(slot.slotStartTimeInUTC).toISOString(), - localEndTime: new Date(slot.slotEndTimeInUTC).toISOString(), + localStartTime: new Date(slot.slotStartTimeInUTC).toLocaleTimeString(), + localEndTime: new Date(slot.slotEndTimeInUTC).toLocaleTimeString(), }) } selectedSlotId={selectedSlot?.slotId} @@ -316,6 +347,7 @@ export default function ExpertProfile( } return null; }, [consultantDetails, selectedSlot]); + const isConsultationPlan = ( plan: ConsultationPlan | SubscriptionPlan, ): plan is ConsultationPlan => { diff --git a/types/slots.ts b/types/slots.ts index 42f05c0..22dc5b9 100644 --- a/types/slots.ts +++ b/types/slots.ts @@ -1,6 +1,9 @@ +import { DayOfWeek } from "@prisma/client"; + export type TSlotTiming = { slotId: string; dateInISO: string; + dayOfWeek: DayOfWeek; slotStartTimeInUTC: string; slotEndTimeInUTC: string; slotOfAvailabilityId: string;