feat: add booking id & booking link columns to /insights/routing (#19697)
* feat: add booking id & booking link columns to /insights/routing * update style * update i18n * update i18n keys * update host * useCopy instead of raw navigator.clipboard
This commit is contained in:
@@ -3001,5 +3001,7 @@
|
||||
"ooo_team_redirect_infinite_not_allowed": "There is already a reverse forwarding between these users.",
|
||||
"previous_ooo_empty_title": "No previous OOO found",
|
||||
"previous": "Previous",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
|
||||
@@ -30,18 +30,22 @@ export type DataTableContextType = {
|
||||
|
||||
export const DataTableContext = createContext<DataTableContextType | null>(null);
|
||||
|
||||
const DEFAULT_ACTIVE_FILTERS: ActiveFilter[] = [];
|
||||
const DEFAULT_SORTING: SortingState = [];
|
||||
const DEFAULT_COLUMN_VISIBILITY: VisibilityState = {};
|
||||
|
||||
export function DataTableProvider({ children }: { children: React.ReactNode }) {
|
||||
const [activeFilters, setActiveFilters] = useQueryState(
|
||||
"activeFilters",
|
||||
parseAsArrayOf(parseAsJson(ZActiveFilter.parse)).withDefault([])
|
||||
parseAsArrayOf(parseAsJson(ZActiveFilter.parse)).withDefault(DEFAULT_ACTIVE_FILTERS)
|
||||
);
|
||||
const [sorting, setSorting] = useQueryState(
|
||||
"sorting",
|
||||
parseAsArrayOf(parseAsJson(ZSorting.parse)).withDefault([])
|
||||
parseAsArrayOf(parseAsJson(ZSorting.parse)).withDefault(DEFAULT_SORTING)
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] = useQueryState<VisibilityState>(
|
||||
"cols",
|
||||
parseAsJson(ZColumnVisibility.parse).withDefault({})
|
||||
parseAsJson(ZColumnVisibility.parse).withDefault(DEFAULT_COLUMN_VISIBILITY)
|
||||
);
|
||||
|
||||
const clearAll = useCallback(
|
||||
|
||||
@@ -6,9 +6,11 @@ import { z } from "zod";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { dataTableFilter, ColumnFilterType } from "@calcom/features/data-table";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useCopy } from "@calcom/lib/hooks/useCopy";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { RoutingFormFieldType } from "@calcom/routing-forms/lib/FieldTypes";
|
||||
import { Badge } from "@calcom/ui";
|
||||
import { Badge, Icon } from "@calcom/ui";
|
||||
|
||||
import { BookedByCell } from "../components/BookedByCell";
|
||||
import { BookingAtCell } from "../components/BookingAtCell";
|
||||
@@ -68,6 +70,32 @@ export const useInsightsColumns = ({
|
||||
return dataTableFilter(cellValue, filterValue);
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("bookingUid", {
|
||||
id: "bookingUid",
|
||||
header: t("uid"),
|
||||
size: 100,
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
cell: (info) => {
|
||||
const bookingUid = info.getValue();
|
||||
if (!bookingUid) return null;
|
||||
return <CopyButton label={bookingUid} value={bookingUid} />;
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("bookingUid", {
|
||||
id: "bookingLink",
|
||||
header: t("link"),
|
||||
size: 100,
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
cell: (info) => {
|
||||
const bookingUid = info.getValue();
|
||||
if (!bookingUid) return null;
|
||||
const bookingUrl = `${WEBAPP_URL}/booking/${bookingUid}`;
|
||||
const displayedUrl = bookingUrl.replace(/^https?:\/\//, "");
|
||||
return <CopyButton label={displayedUrl} value={bookingUrl} />;
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("bookingAttendees", {
|
||||
id: "bookingAttendees",
|
||||
header: t("routing_form_insights_booked_by"),
|
||||
@@ -225,3 +253,29 @@ export const useInsightsColumns = ({
|
||||
];
|
||||
}, [isHeadersSuccess, headers]);
|
||||
};
|
||||
|
||||
function CopyButton({ label, value }: { label: string; value: string }) {
|
||||
const { copyToClipboard, isCopied } = useCopy();
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<button
|
||||
className="flex w-full items-center gap-1 overflow-hidden"
|
||||
title={value}
|
||||
onClick={() => {
|
||||
copyToClipboard(value);
|
||||
}}>
|
||||
{!isCopied && (
|
||||
<>
|
||||
<span className="truncate">{label}</span>
|
||||
<Icon name="clipboard" className="shrink-0" size={14} />
|
||||
</>
|
||||
)}
|
||||
{isCopied && (
|
||||
<>
|
||||
<span className="grow truncate text-left">{t("copied")}</span>
|
||||
<Icon name="check" className="shrink-0" size={14} />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,22 +27,37 @@ export const useInsightsFacetedUniqueValues = ({
|
||||
teamId: number | undefined;
|
||||
isAll: boolean;
|
||||
}) => {
|
||||
const { data: forms } = trpc.viewer.insights.getRoutingFormsForFilters.useQuery({
|
||||
userId,
|
||||
teamId,
|
||||
isAll,
|
||||
});
|
||||
const { data: forms } = trpc.viewer.insights.getRoutingFormsForFilters.useQuery(
|
||||
{
|
||||
userId,
|
||||
teamId,
|
||||
isAll,
|
||||
},
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
}
|
||||
);
|
||||
|
||||
const { data: users } = trpc.viewer.insights.userList.useQuery({
|
||||
teamId,
|
||||
isAll,
|
||||
});
|
||||
const { data: users } = trpc.viewer.insights.userList.useQuery(
|
||||
{
|
||||
teamId,
|
||||
isAll,
|
||||
},
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
}
|
||||
);
|
||||
|
||||
const { data: eventTypes } = trpc.viewer.insights.eventTypeList.useQuery({
|
||||
teamId,
|
||||
userId,
|
||||
isAll,
|
||||
});
|
||||
const { data: eventTypes } = trpc.viewer.insights.eventTypeList.useQuery(
|
||||
{
|
||||
teamId,
|
||||
userId,
|
||||
isAll,
|
||||
},
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
}
|
||||
);
|
||||
|
||||
return useCallback(
|
||||
(_: Table<any>, columnId: string) => (): Map<FacetedValue, number> => {
|
||||
|
||||
Reference in New Issue
Block a user