Files
calendar/packages/ui/components/segmented-control/SegmentedControl.tsx
T
Hariom BalharaGitHubUdit TakkarDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
a7fd7890a7 feat: integrate BookingHistory with Bookings V3 design (#26301)
* Integrate BookingHistory with Bookings V3 design

* Enhance booking features by integrating booking audit functionality

- Updated the booking page to retrieve user feature statuses for "bookings-v3" and "booking-audit".
- Modified BookingDetailsSheet and BookingListContainer components to accept and utilize the new bookingAuditEnabled prop.
- Adjusted the BookingHistory display logic to conditionally render based on the bookingAuditEnabled state.
- Refactored SegmentedControl to support generic types for better type safety.

This change improves the user experience by allowing conditional access to booking audit features based on user permissions.

* Refactor BookingDetailsSheet to manage active segment state with Zustand store

- Removed local state management for active segment in BookingDetailsSheet and integrated Zustand store for better state synchronization.
- Introduced useActiveSegmentFromUrl hook to sync active segment with URL query parameters.
- Updated BookingDetailsSheet to handle derived active segment logic based on bookingAuditEnabled state.
- Adjusted SegmentedControl to ensure it defaults to "info" when activeSegment is null.

This refactor enhances the maintainability and responsiveness of the booking details component.

* refactor: rename useBiDirectionalSyncBetweenZustandAndNuqs to useBiDirectionalSyncBetweenStoreAndUrl

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 16:21:35 +05:30

75 lines
2.8 KiB
TypeScript

import classNames from "@calcom/ui/classNames";
export type SegmentedControlData<T extends string> = T | { value: T; label: string };
export interface SegmentedControlProps<T extends string> {
data: SegmentedControlData<T>[];
value: T;
onChange: (value: T) => void;
disabled?: boolean;
className?: string;
"data-testid"?: string;
}
const SegmentedControl = function <T extends string>({
data,
value,
onChange,
disabled = false,
className,
"data-testid": dataTestId,
...props
}: SegmentedControlProps<T>) {
const handleChange = (newValue: T) => {
if (!disabled) {
onChange(newValue);
}
};
return (
<div
className={classNames("max-w-full", className)}
data-testid={dataTestId}
{...props}>
<div
className="no-scrollbar flex space-x-0.5 overflow-x-scroll rounded-lg bg-subtle p-0.5"
role="radiogroup">
{data.map((item, idx) => {
const itemValue = typeof item === "string" ? item : item.value;
const itemLabel = typeof item === "string" ? item : item.label;
const isActive = value === itemValue;
const inputId = `segmented-control-${itemValue}-${idx}`;
return (
<label
key={itemValue}
htmlFor={inputId}
className={classNames(
"inline-flex h-fit w-full items-center justify-center whitespace-nowrap rounded-lg p-1 text-md font-medium leading-none transition md:mb-0",
"not-disabled:hover:shadow-outline-gray-hover not-disabled:active:shadow-outline-gray-active",
isActive
? "bg-default text-emphasis shadow-outline-gray-rested ring-inset ring-subtle"
: "text-subtle",
disabled ? "pointer-events-none opacity-30" : "cursor-pointer"
)}>
<input
type="radio"
id={inputId}
value={itemValue}
checked={isActive}
onChange={() => handleChange(itemValue)}
disabled={disabled}
className="sr-only"
aria-checked={isActive}
/>
<span>{itemLabel}</span>
</label>
);
})}
</div>
</div>
);
};
export default SegmentedControl;