Compare commits
2 Commits
main
...
gh-readonl
Author | SHA1 | Date | |
---|---|---|---|
781e0e361d | |||
e4a16a86a4 |
|
@ -51,15 +51,17 @@ export default function Login({
|
||||||
}: inferSSRProps<typeof _getServerSideProps> & WithNonceProps) {
|
}: inferSSRProps<typeof _getServerSideProps> & WithNonceProps) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const formSchema = z.object({
|
const formSchema = z
|
||||||
email: z
|
.object({
|
||||||
.string()
|
email: z
|
||||||
.min(1, `${t("error_required_field")}`)
|
.string()
|
||||||
.email(`${t("enter_valid_email")}`),
|
.min(1, `${t("error_required_field")}`)
|
||||||
password: z.string().min(1, `${t("error_required_field")}`),
|
.email(`${t("enter_valid_email")}`),
|
||||||
});
|
password: z.string().min(1, `${t("error_required_field")}`),
|
||||||
|
})
|
||||||
|
// Passthrough other fields like totpCode
|
||||||
|
.passthrough();
|
||||||
const methods = useForm<LoginValues>({ resolver: zodResolver(formSchema) });
|
const methods = useForm<LoginValues>({ resolver: zodResolver(formSchema) });
|
||||||
|
|
||||||
const { register, formState } = methods;
|
const { register, formState } = methods;
|
||||||
const [twoFactorRequired, setTwoFactorRequired] = useState(!!totpEmail || false);
|
const [twoFactorRequired, setTwoFactorRequired] = useState(!!totpEmail || false);
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { Fragment, useState, useEffect } from "react";
|
import { Fragment, useState } from "react";
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { AnimatedPopover } from "@calcom/ui";
|
import { AnimatedPopover } from "@calcom/ui";
|
||||||
|
import { Checkbox } from "@calcom/ui";
|
||||||
|
|
||||||
import { groupBy } from "../groupBy";
|
import { groupBy } from "../groupBy";
|
||||||
|
import { useFilterQuery } from "../lib/useFilterQuery";
|
||||||
|
|
||||||
export type IEventTypesFilters = RouterOutputs["viewer"]["eventTypes"]["listWithTeam"];
|
export type IEventTypesFilters = RouterOutputs["viewer"]["eventTypes"]["listWithTeam"];
|
||||||
export type IEventTypeFilter = IEventTypesFilters[0];
|
export type IEventTypeFilter = IEventTypesFilters[0];
|
||||||
|
@ -27,24 +29,32 @@ type GroupedEventTypeState = Record<
|
||||||
export const EventTypeFilter = () => {
|
export const EventTypeFilter = () => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const { data: user } = useSession();
|
const { data: user } = useSession();
|
||||||
const eventTypes = trpc.viewer.eventTypes.listWithTeam.useQuery();
|
const { data: query, pushItemToKey, removeItemByKeyAndValue } = useFilterQuery();
|
||||||
|
|
||||||
const [groupedEventTypes, setGroupedEventTypes] = useState<GroupedEventTypeState>();
|
const [groupedEventTypes, setGroupedEventTypes] = useState<GroupedEventTypeState>();
|
||||||
// Will be handled up the tree to redirect
|
|
||||||
useEffect(() => {
|
|
||||||
if (!eventTypes.data) return;
|
|
||||||
// Group event types by team
|
|
||||||
const grouped = groupBy<IEventTypeFilter>(
|
|
||||||
eventTypes.data.filter((el) => el.team),
|
|
||||||
(item) => item?.team?.name || ""
|
|
||||||
); // Add the team name
|
|
||||||
const individualEvents = eventTypes.data.filter((el) => !el.team);
|
|
||||||
// push indivdual events to the start of grouped array
|
|
||||||
setGroupedEventTypes({ user_own_event_types: individualEvents, ...grouped });
|
|
||||||
}, [eventTypes.data, user]);
|
|
||||||
|
|
||||||
if (!user) return null;
|
const eventTypes = trpc.viewer.eventTypes.listWithTeam.useQuery(undefined, {
|
||||||
|
onSuccess: (data) => {
|
||||||
|
// Will be handled up the tree to redirect
|
||||||
|
// Group event types by team
|
||||||
|
const grouped = groupBy<IEventTypeFilter>(
|
||||||
|
data.filter((el) => el.team),
|
||||||
|
(item) => item?.team?.name || ""
|
||||||
|
); // Add the team name
|
||||||
|
const individualEvents = data.filter((el) => !el.team);
|
||||||
|
// push indivdual events to the start of grouped array
|
||||||
|
setGroupedEventTypes(
|
||||||
|
individualEvents.length > 0 ? { user_own_event_types: individualEvents, ...grouped } : grouped
|
||||||
|
);
|
||||||
|
},
|
||||||
|
enabled: !!user,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
if (!eventTypes.data) return null;
|
||||||
|
|
||||||
|
const isNotEmpty = eventTypes.data.length > 0;
|
||||||
|
|
||||||
|
return eventTypes.status === "success" && isNotEmpty ? (
|
||||||
<AnimatedPopover text={t("event_type")}>
|
<AnimatedPopover text={t("event_type")}>
|
||||||
<div className="">
|
<div className="">
|
||||||
{groupedEventTypes &&
|
{groupedEventTypes &&
|
||||||
|
@ -54,25 +64,23 @@ export const EventTypeFilter = () => {
|
||||||
{teamName === "user_own_event_types" ? t("individual") : teamName}
|
{teamName === "user_own_event_types" ? t("individual") : teamName}
|
||||||
</div>
|
</div>
|
||||||
{groupedEventTypes[teamName].map((eventType) => (
|
{groupedEventTypes[teamName].map((eventType) => (
|
||||||
<Fragment key={eventType.id}>
|
<div key={eventType.id} className="item-center flex px-4 py-1.5">
|
||||||
<div className="item-center flex px-4 py-[6px]">
|
<Checkbox
|
||||||
<p className="text-default block self-center truncate text-sm font-medium">
|
checked={query.eventTypeIds?.includes(eventType.id)}
|
||||||
{eventType.title}
|
onChange={(e) => {
|
||||||
</p>
|
if (e.target.checked) {
|
||||||
<div className="ml-auto">
|
pushItemToKey("eventTypeIds", eventType.id);
|
||||||
<input
|
} else if (!e.target.checked) {
|
||||||
type="checkbox"
|
removeItemByKeyAndValue("eventTypeIds", eventType.id);
|
||||||
name=""
|
}
|
||||||
id=""
|
}}
|
||||||
className="text-primary-600 focus:ring-primary-500 border-default h-4 w-4 rounded ltr:mr-2 rtl:ml-2 "
|
description={eventType.title}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
))}
|
))}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</AnimatedPopover>
|
</AnimatedPopover>
|
||||||
);
|
) : null;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { Fragment, ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
import { Fragment } from "react";
|
||||||
|
|
||||||
|
import { EventTypeFilter } from "./EventTypeFilter";
|
||||||
import { PeopleFilter } from "./PeopleFilter";
|
import { PeopleFilter } from "./PeopleFilter";
|
||||||
import { TeamsMemberFilter } from "./TeamFilter";
|
import { TeamsMemberFilter } from "./TeamFilter";
|
||||||
|
|
||||||
type FilterTypes = "teams" | "people";
|
type FilterTypes = "teams" | "people" | "eventType";
|
||||||
|
|
||||||
type Filter = {
|
type Filter = {
|
||||||
name: FilterTypes;
|
name: FilterTypes;
|
||||||
|
@ -25,6 +27,12 @@ const filters: Filter[] = [
|
||||||
controllingQueryParams: ["usersId"],
|
controllingQueryParams: ["usersId"],
|
||||||
showByDefault: true,
|
showByDefault: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "eventType",
|
||||||
|
component: <EventTypeFilter />,
|
||||||
|
controllingQueryParams: ["eventTypeId"],
|
||||||
|
showByDefault: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function FiltersContainer() {
|
export function FiltersContainer() {
|
||||||
|
|
|
@ -102,6 +102,15 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
eventTypeIds: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
eventTypeId: {
|
||||||
|
in: input.filters?.eventTypeIds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const filtersCombined: Prisma.BookingWhereInput[] =
|
const filtersCombined: Prisma.BookingWhereInput[] =
|
||||||
|
|
Loading…
Reference in New Issue
Block a user