diff --git a/packages/atoms/availability-list/components/availability/index.tsx b/packages/atoms/availability-list/components/availability/index.tsx
new file mode 100644
index 0000000000..c8465ed40e
--- /dev/null
+++ b/packages/atoms/availability-list/components/availability/index.tsx
@@ -0,0 +1,120 @@
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+} from "@/components/ui/dropdown-menu";
+import { Toaster } from "@/components/ui/toaster";
+import { useToast } from "@/components/ui/use-toast";
+import type { Schedule } from "availability-list";
+import { Globe, MoreHorizontal, Star, Copy, Trash } from "lucide-react";
+import { Fragment } from "react";
+
+import { availabilityAsString } from "@calcom/lib/availability";
+
+type AvailabilityProps = {
+ schedule: Schedule;
+ isDeletable: boolean;
+ updateDefault: ({ scheduleId, isDefault }: { scheduleId: number; isDefault: boolean }) => void;
+ duplicateFunction: ({ scheduleId }: { scheduleId: number }) => void;
+ deleteFunction: ({ scheduleId }: { scheduleId: number }) => void;
+ displayOptions?: {
+ timeZone?: string;
+ hour12?: boolean;
+ };
+};
+
+export function Availability({
+ schedule,
+ isDeletable,
+ displayOptions,
+ updateDefault,
+ duplicateFunction,
+ deleteFunction,
+}: AvailabilityProps) {
+ const { toast } = useToast();
+
+ return (
+
+
+
+
+
+
+
+
+ {!schedule.isDefault && (
+ {
+ updateDefault({
+ scheduleId: schedule.id,
+ isDefault: true,
+ });
+ }}
+ className="min-w-40 focus:ring-mute min-w-40 focus:ring-muted">
+
+ Set as default
+
+ )}
+ {
+ duplicateFunction({
+ scheduleId: schedule.id,
+ });
+ }}>
+
+ Duplicate
+
+ {
+ if (!isDeletable) {
+ toast({
+ description: "You are required to have at least one schedule",
+ });
+ } else {
+ deleteFunction({
+ scheduleId: schedule.id,
+ });
+ }
+ }}>
+
+ Delete
+
+
+
+
+
+
+ );
+}
diff --git a/packages/atoms/availability-list/components/empty-screen/index.tsx b/packages/atoms/availability-list/components/empty-screen/index.tsx
new file mode 100644
index 0000000000..6cf320e20d
--- /dev/null
+++ b/packages/atoms/availability-list/components/empty-screen/index.tsx
@@ -0,0 +1,70 @@
+import { Button } from "@/components/ui/button";
+import type { LucideIcon as IconType } from "lucide-react";
+import type { ReactNode } from "react";
+import React from "react";
+
+import { classNames } from "@calcom/lib";
+import type { SVGComponent } from "@calcom/types/SVGComponent";
+
+type EmptyScreenProps = {
+ Icon?: SVGComponent | IconType;
+ avatar?: React.ReactElement;
+ headline: string | React.ReactElement;
+ description?: string | React.ReactElement;
+ buttonText?: string;
+ buttonOnClick?: (event: React.MouseEvent) => void;
+ buttonRaw?: ReactNode; // Used incase you want to provide your own button.
+ border?: boolean;
+ dashedBorder?: boolean;
+};
+
+export function EmptyScreen({
+ Icon,
+ avatar,
+ headline,
+ description,
+ buttonText,
+ buttonOnClick,
+ buttonRaw,
+ border = true,
+ dashedBorder = true,
+ className,
+}: EmptyScreenProps & React.HTMLAttributes) {
+ return (
+ <>
+
+ {!avatar ? null : (
+
{avatar}
+ )}
+ {!Icon ? null : (
+
+
+
+ )}
+
+
+ {headline}
+
+ {description && (
+
+ {description}
+
+ )}
+ {buttonOnClick && buttonText &&
}
+ {buttonRaw}
+
+
+ >
+ );
+}
diff --git a/packages/atoms/availability-list/components/form/index.tsx b/packages/atoms/availability-list/components/form/index.tsx
new file mode 100644
index 0000000000..fd72a3c99e
--- /dev/null
+++ b/packages/atoms/availability-list/components/form/index.tsx
@@ -0,0 +1,39 @@
+import type { ReactElement, Ref } from "react";
+import React, { forwardRef } from "react";
+import type { FieldValues, SubmitHandler, UseFormReturn } from "react-hook-form";
+import { FormProvider } from "react-hook-form";
+
+type FormProps = { form: UseFormReturn; handleSubmit: SubmitHandler } & Omit<
+ JSX.IntrinsicElements["form"],
+ "onSubmit"
+>;
+
+const PlainForm = (props: FormProps, ref: Ref) => {
+ const { form, handleSubmit, ...passThrough } = props;
+
+ return (
+
+
+
+ );
+};
+
+export const Form = forwardRef(PlainForm) as (
+ p: FormProps & { ref?: Ref }
+) => ReactElement;
diff --git a/packages/atoms/availability-list/components/new-schedule-button/index.tsx b/packages/atoms/availability-list/components/new-schedule-button/index.tsx
new file mode 100644
index 0000000000..7494b15971
--- /dev/null
+++ b/packages/atoms/availability-list/components/new-schedule-button/index.tsx
@@ -0,0 +1,68 @@
+import {
+ Dialog,
+ DialogTrigger,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { useForm } from "react-hook-form";
+
+import type { HttpError } from "@calcom/lib/http-error";
+import { Plus } from "@calcom/ui/components/icon";
+
+import { Button } from "../../../src/components/ui/button";
+import { Form } from "../form";
+import type { Schedule } from ".prisma/client";
+
+// create mutation handler to be handled outside the component
+// then passed in as a prop
+// TODO: translations can be taken care of later
+
+type NewScheduleButtonProps = {
+ name?: string;
+ createMutation: (values: {
+ onSucess: (schedule: Schedule) => void;
+ onError: (err: HttpError) => void;
+ }) => void;
+};
+
+export function NewScheduleButton({ name = "new-schedule", createMutation }: NewScheduleButtonProps) {
+ const form = useForm<{
+ name: string;
+ }>();
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/atoms/availability-list/export.ts b/packages/atoms/availability-list/export.ts
new file mode 100644
index 0000000000..cf8a1d71d4
--- /dev/null
+++ b/packages/atoms/availability-list/export.ts
@@ -0,0 +1,3 @@
+export { AvailabilityList } from ".";
+export { Availability } from "./components/availability";
+export * from "../types";
diff --git a/packages/atoms/availability-list/index.tsx b/packages/atoms/availability-list/index.tsx
new file mode 100644
index 0000000000..3c71f07dc1
--- /dev/null
+++ b/packages/atoms/availability-list/index.tsx
@@ -0,0 +1,74 @@
+import { NewScheduleButton } from "availability-list/components/new-schedule-button/NewScheduleButton";
+
+import type { HttpError } from "@calcom/lib/http-error";
+import { Clock } from "@calcom/ui/components/icon";
+
+import { Availability } from "./components/availability";
+import { EmptyScreen } from "./components/empty-screen";
+
+export type Schedule = {
+ isDefault: boolean;
+ id: number;
+ name: string;
+ availability: {
+ id: number;
+ startTime: Date;
+ endTime: Date;
+ userId?: number;
+ eventTypeId?: number;
+ date?: Date;
+ days: number[];
+ scheduleId?: number;
+ }[];
+ timezone?: string;
+};
+
+type AvailabilityListProps = {
+ schedules: Schedule[] | [];
+ onCreateMutation: (values: {
+ onSucess: (schedule: Schedule) => void;
+ onError: (err: HttpError) => void;
+ }) => void;
+ updateMutation: ({ scheduleId, isDefault }: { scheduleId: number; isDefault: boolean }) => void;
+ duplicateMutation: ({ scheduleId }: { scheduleId: number }) => void;
+ deleteMutation: ({ scheduleId }: { scheduleId: number }) => void;
+};
+
+export function AvailabilityList({
+ schedules,
+ onCreateMutation,
+ updateMutation,
+ duplicateMutation,
+ deleteMutation,
+}: AvailabilityListProps) {
+ if (schedules.length === 0) {
+ return (
+
+ }
+ />
+
+ );
+ }
+
+ return (
+
+
+ {schedules.map((schedule) => (
+
+ ))}
+
+
+ );
+}