diff --git a/apps/anvil/src/sign-in/sign-in.controller.ts b/apps/anvil/src/sign-in/sign-in.controller.ts index eeadd3a..f186cf0 100644 --- a/apps/anvil/src/sign-in/sign-in.controller.ts +++ b/apps/anvil/src/sign-in/sign-in.controller.ts @@ -16,6 +16,7 @@ import { ParseIntPipe, Patch, Post, + Query, Req, UseGuards, UseInterceptors, @@ -177,7 +178,7 @@ export class SignInController { @Get("/common-reasons") @IsRep() - async getPopularSignInReasons(@Param("location") location: LocationName) { - return this.signInService.getPopularReasons(location); + async getPopularSignInReasons(@Param("location") location: LocationName, @Query("rep") rep: string) { + return this.signInService.getPopularReasons(location, rep === "true"); } } diff --git a/apps/anvil/src/sign-in/sign-in.service.ts b/apps/anvil/src/sign-in/sign-in.service.ts index 57a10f6..c99d22b 100644 --- a/apps/anvil/src/sign-in/sign-in.service.ts +++ b/apps/anvil/src/sign-in/sign-in.service.ts @@ -811,41 +811,26 @@ export class SignInService implements OnModuleInit { ); } - async getPopularReasons(name: LocationName) { - return await this.dbService.query( - e.select( - e.op( - e.select( - e.group( - e.select(e.sign_in.SignIn, (sign_in) => ({ - filter: e.all( - e.set( - e.op(sign_in.location.name, "=", e.cast(e.sign_in.LocationName, name)), - e.op(sign_in.reason.name, "in", e.set(REP_ON_SHIFT, REP_OFF_SHIFT, PERSONAL)), - ), - ), - })), - (sign_in) => ({ - by: { reason: sign_in.reason }, - }), + async getPopularReasons(name: LocationName, rep: boolean) { + return await this.dbService + .query( + e.select({ + default_: e.select(e.sign_in.Reason, (reason) => ({ + filter: e.op(reason.name, "in", e.set(...(rep ? [REP_ON_SHIFT, REP_OFF_SHIFT] : []), PERSONAL)), + order_by: e.op( + // Personal then on then off + 0, + "if", + e.op(e.assert_single(reason.name), "=", PERSONAL), + "else", + e.op(1, "if", e.op(e.assert_single(reason.name), "=", REP_ON_SHIFT), "else", 2), ), - (group) => ({ - name: e.assert_single(group.elements.reason.name), - category: e.assert_single(group.elements.reason.category), - id_: e.assert_single(group.elements.reason.id), - count: e.count(group.elements), - order_by: e.op( - // Personal then on then off - 0, - "if", - e.op(group.elements.reason.name, "=", PERSONAL), - "else", - e.op(1, "if", e.op(group.elements.reason.name, "=", REP_ON_SHIFT), "else", 2), - ), - }), - ), - "intersect", - e.select( + id_: reason.id, + name: true, + category: true, + count: e.select(0), + })), + common: e.select( e.group( e.select(e.sign_in.SignIn, (sign_in) => ({ filter: e.all( @@ -869,17 +854,11 @@ export class SignInService implements OnModuleInit { expression: e.count(group.elements), direction: e.DESC, }, - limit: 3, + limit: rep ? 3 : 5, }), ), - ), - (reason) => ({ - name: e.assert_exists(reason.name), - category: e.assert_exists(reason.category), - id: e.assert_exists(reason.id_), - count: reason.count, }), - ), - ); + ) + .then(({ common, default_ }) => [...default_, ...common].map((reason) => ({ id: reason.id_, ...reason }))); } } diff --git a/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReason.tsx b/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReason.tsx index 0a8e703..9dda8ef 100644 --- a/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReason.tsx +++ b/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReason.tsx @@ -2,9 +2,14 @@ import { Category } from "@/components/icons/SignInReason.tsx"; import { cn } from "@/lib/utils.ts"; import { PartialReason } from "@ignis/types/sign_in.ts"; import { Badge } from "@ui/components/ui/badge.tsx"; -import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@ui/components/ui/tooltip.tsx"; +import { Kbd } from "@ui/components/ui/kbd"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@ui/components/ui/tooltip.tsx"; -export const SignInReason = ({ reason, className }: { reason: PartialReason; className?: string }) => { +export const SignInReason = ({ + reason, + index, + className, +}: { reason: PartialReason; index?: number; className?: string }) => { return ( @@ -14,6 +19,7 @@ export const SignInReason = ({ reason, className }: { reason: PartialReason; cla variant="default" className={cn("max-w-48 rounded-sm shadow-lg justify-center items-center", className)} > + {index !== undefined ? F{index + 1} : null} {} {reason.category === "UNIVERSITY_MODULE" ? reason.name.split(" ")[0] : reason.name} diff --git a/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReasonInput.tsx b/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReasonInput.tsx index 10811bd..de59448 100644 --- a/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReasonInput.tsx +++ b/apps/forge/src/routes/_authenticated/_reponly/sign-in/actions/-components/SignInReasonInput.tsx @@ -96,9 +96,10 @@ export const SignInReasonInput: FlowStepComponent = ({ onSecondary, onPrimary }) } } else if (event.key === "Escape") { handleClearReason(); - } else if (event.key >= "1" && event.key <= "8") { - const index = Number.parseInt(event.key) - 1; + } else if (event.key >= "F1" && event.key <= "F6") { + const index = Number.parseInt(event.key.slice(1)) - 1; if (commonReasons && index < commonReasons.length) { + event.preventDefault(); // Prevent default F-key behavior handleSelectReason(commonReasons[index]); } } @@ -128,7 +129,7 @@ export const SignInReasonInput: FlowStepComponent = ({ onSecondary, onPrimary }) Sign-In Reason Input Start typing to match your sign-in reason or pick a recent common reason: - {/* {commonReasonsError ? ( // FIXME + {commonReasonsError ? ( // FIXME `Failed to fetch common reasons: ${extractError(commonReasonsError)}` ) : commonReasonsIsLoading ? ( @@ -136,12 +137,11 @@ export const SignInReasonInput: FlowStepComponent = ({ onSecondary, onPrimary })
{commonReasons?.map((reason, index) => (
handleSelectReason(reason)} className="flex hover:cursor-pointer m-1"> - {index + 1} - +
))}
- )} */} + )}
{isLoading && } @@ -155,7 +155,7 @@ export const SignInReasonInput: FlowStepComponent = ({ onSecondary, onPrimary }) value={inputValue} onChange={handleInputChange} onKeyDown={handleKeyDown} - placeholder="Start typing a reason or press 1-8 for quick selection..." + placeholder="Start typing a reason or press F1-F6 for quick selection..." className="mb-2" /> {inputValue && ( diff --git a/apps/forge/src/services/sign_in/signInReasonService.ts b/apps/forge/src/services/sign_in/signInReasonService.ts index 2a6a281..8996db1 100644 --- a/apps/forge/src/services/sign_in/signInReasonService.ts +++ b/apps/forge/src/services/sign_in/signInReasonService.ts @@ -19,8 +19,10 @@ export const fetchSignInReasons = async (): Promise => { return response.data; }; -export const getCommonReasons = async (location: LocationName): Promise => { - const { data } = await axiosInstance.get(`/location/${location}/common-reasons`); +export const getCommonReasons = async (location: LocationName, rep?: boolean): Promise => { + const { data } = await axiosInstance.get(`/location/${location}/common-reasons`, { + params: { rep: rep ? "true" : "" }, + }); return data; }; diff --git a/packages/ui/components/ui/kbd.tsx b/packages/ui/components/ui/kbd.tsx new file mode 100644 index 0000000..82ed36a --- /dev/null +++ b/packages/ui/components/ui/kbd.tsx @@ -0,0 +1,18 @@ +import { cn } from "@/lib/utils"; +import React from "react"; + +export const Kbd = ({ + children, + className, + ...props +}: React.DetailedHTMLProps, HTMLDivElement>) => ( +
+ {children} +
+);