Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ AND FS."NumberOfQuestionsAnswered" > 0
WHERE
"ElectionRoundId" = ANY (@electionRoundIds)
AND "NumberOfQuestionsAnswered" > 0
) AS "NumberOfFormSubmissions";
) AS ""NumberOfQuestionsAnswered"";
-----------------------------

-- number of questions answered
Expand Down
2 changes: 2 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@tiptap/react": "^2.8.0",
"@tiptap/starter-kit": "^2.8.0",
"@types/lodash": "^4.17.7",
"@types/papaparse": "^5.3.15",
"@uidotdev/usehooks": "^2.4.1",
"axios": "^1.6.2",
"chart.js": "^4.4.2",
Expand All @@ -74,6 +75,7 @@
"i18next-browser-languagedetector": "^8.0.0",
"lodash": "^4.17.21",
"lucide-react": "^0.294.0",
"papaparse": "^5.4.1",
"qs": "^6.12.0",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
Expand Down
18 changes: 18 additions & 0 deletions web/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion web/src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Breadcrumbs from './Breadcrumbs/Breadcrumbs';
import BackButton from './Breadcrumbs/BackButton';

interface LayoutProps {
title: string;
title?: string;
subtitle?: string;
enableBreadcrumbs?: boolean;
breadcrumbs?: ReactNode;
Expand Down
2 changes: 0 additions & 2 deletions web/src/components/ui/dual-range-slider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import * as React from 'react';
import * as SliderPrimitive from '@radix-ui/react-slider';

Expand Down
4 changes: 2 additions & 2 deletions web/src/components/ui/file-uploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export function FileUploader(props: FileUploaderProps) {

return (
<div className="relative flex flex-col gap-6 overflow-hidden">
<Dropzone
{!files?.length || (files?.length ?? 0) < maxFileCount ?<Dropzone
onDrop={onDrop}
accept={accept}
maxSize={maxSize}
Expand Down Expand Up @@ -194,7 +194,7 @@ export function FileUploader(props: FileUploaderProps) {
)}
</div>
)}
</Dropzone>
</Dropzone> : null}
{files?.length ? (
<div className="flex flex-col gap-4 max-h-48">
{files?.map((file, index) => (
Expand Down
107 changes: 65 additions & 42 deletions web/src/components/ui/stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ const StepperProvider = ({ value, children }: StepperContextProviderProps) => {

// <---------- HOOKS ---------->

function usePrevious<T>(value: T): T | undefined {
const ref = React.useRef<T>()

React.useEffect(() => {
ref.current = value
}, [value])

return ref.current
}

function useStepper() {
const context = React.useContext(StepperContext)

Expand All @@ -98,6 +108,8 @@ function useStepper() {
const isLastStep = context.activeStep === context.steps.length - 1
const hasCompletedAllSteps = context.activeStep === context.steps.length

const previousActiveStep = usePrevious(context.activeStep)

const currentStep = context.steps[context.activeStep]
const isOptionalStep = !!currentStep?.optional

Expand All @@ -110,6 +122,7 @@ function useStepper() {
isOptionalStep,
isDisabledStep,
currentStep,
previousActiveStep,
}
}

Expand Down Expand Up @@ -147,7 +160,7 @@ interface StepOptions {
responsive?: boolean
checkIcon?: IconType
errorIcon?: IconType
onClickStep?: (step: number) => void
onClickStep?: (step: number, setStep: (step: number) => void) => void
mobileBreakpoint?: string
variant?: "circle" | "circle-alt" | "line"
expandVerticalSteps?: boolean
Expand Down Expand Up @@ -262,6 +275,7 @@ const Stepper = React.forwardRef<HTMLDivElement, StepperProps>(
expandVerticalSteps,
steps,
scrollTracking,
styles,
}}
>
<div
Expand Down Expand Up @@ -365,7 +379,7 @@ interface StepProps extends React.HTMLAttributes<HTMLLIElement> {
errorIcon?: IconType
isCompletedStep?: boolean
isKeepError?: boolean
onClickStep?: (step: number) => void
onClickStep?: (step: number, setStep: (step: number) => void) => void
}

interface StepSharedProps extends StepProps {
Expand Down Expand Up @@ -452,12 +466,16 @@ type VerticalStepProps = StepSharedProps & {
}

const verticalStepVariants = cva(
"flex flex-col relative transition-all duration-200",
[
"flex flex-col relative transition-all duration-200",
"data-[completed=true]:[&:not(:last-child)]:after:bg-primary",
"data-[invalid=true]:[&:not(:last-child)]:after:bg-destructive",
],
{
variants: {
variant: {
circle: cn(
"pb-[var(--step-gap)] gap-[var(--step-gap)]",
"[&:not(:last-child)]:pb-[var(--step-gap)] [&:not(:last-child)]:gap-[var(--step-gap)]",
"[&:not(:last-child)]:after:content-[''] [&:not(:last-child)]:after:w-[2px] [&:not(:last-child)]:after:bg-border",
"[&:not(:last-child)]:after:inset-x-[calc(var(--step-icon-size)/2)]",
"[&:not(:last-child)]:after:absolute",
Expand Down Expand Up @@ -501,12 +519,17 @@ const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
scrollTracking,
orientation,
steps,
setStep,
isLastStep: isLastStepCurrentStep,
previousActiveStep,
} = useStepper()

const opacity = hasVisited ? 1 : 0.8
const localIsLoading = isLoading || state === "loading"
const localIsError = isError || state === "error"

const isLastStep = index === steps.length - 1

const active =
variant === "line" ? isCompletedStep || isCurrentStep : isCompletedStep
const checkIcon = checkIconProp || checkIconContext
Expand All @@ -516,7 +539,27 @@ const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
if (!expandVerticalSteps) {
return (
<Collapsible open={isCurrentStep}>
<CollapsibleContent className="overflow-hidden data-[state=open]:animate-collapsible-down data-[state=closed]:animate-collapsible-up">
<CollapsibleContent
ref={(node) => {
if (
// If the step is the first step and the previous step
// was the last step or if the step is not the first step
// This prevents initial scrolling when the stepper
// is located anywhere other than the top of the view.
scrollTracking &&
((index === 0 &&
previousActiveStep &&
previousActiveStep === steps.length) ||
(index && index > 0))
) {
node?.scrollIntoView({
behavior: "smooth",
block: "center",
})
}
}}
className="overflow-hidden data-[state=open]:animate-collapsible-down data-[state=closed]:animate-collapsible-up"
>
{children}
</CollapsibleContent>
</Collapsible>
Expand All @@ -533,8 +576,7 @@ const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
verticalStepVariants({
variant: variant?.includes("circle") ? "circle" : "line",
}),
isCompletedStep &&
"[&:not(:last-child)]:after:bg-blue-500 [&:not(:last-child)]:after:data-[invalid=true]:bg-destructive",
isLastStepCurrentStep && "gap-[var(--step-gap)]",
styles?.["vertical-step"]
)}
data-optional={steps[index || 0]?.optional}
Expand All @@ -543,7 +585,8 @@ const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
data-clickable={clickable || !!onClickStep}
data-invalid={localIsError}
onClick={() =>
onClickStep?.(index || 0) || onClickStepGeneral?.(index || 0)
onClickStep?.(index || 0, setStep) ||
onClickStepGeneral?.(index || 0, setStep)
}
>
<div
Expand All @@ -553,7 +596,7 @@ const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
"stepper__vertical-step-container",
"flex items-center",
variant === "line" &&
"border-s-[3px] data-[active=true]:border-blue-500 py-2 ps-3",
"border-s-[3px] data-[active=true]:border-primary py-2 ps-3",
styles?.["vertical-step-container"]
)}
>
Expand All @@ -580,17 +623,9 @@ const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
/>
</div>
<div
ref={(node) => {
if (scrollTracking) {
node?.scrollIntoView({
behavior: "smooth",
block: "center",
})
}
}}
className={cn(
"stepper__vertical-step-content",
"min-h-4",
!isLastStep && "min-h-4",
variant !== "line" && "ps-[--step-icon-size]",
variant === "line" && orientation === "vertical" && "min-h-0",
styles?.["vertical-step-content"]
Expand All @@ -617,6 +652,7 @@ const HorizontalStep = React.forwardRef<HTMLDivElement, StepSharedProps>(
errorIcon: errorIconContext,
styles,
steps,
setStep,
} = useStepper()

const {
Expand Down Expand Up @@ -653,22 +689,22 @@ const HorizontalStep = React.forwardRef<HTMLDivElement, StepSharedProps>(
"[&:not(:last-child)]:flex-1",
"[&:not(:last-child)]:after:transition-all [&:not(:last-child)]:after:duration-200",
"[&:not(:last-child)]:after:content-[''] [&:not(:last-child)]:after:h-[2px] [&:not(:last-child)]:after:bg-border",
"data-[completed=true]:[&:not(:last-child)]:after:bg-primary",
"data-[invalid=true]:[&:not(:last-child)]:after:bg-destructive",
variant === "circle-alt" &&
"justify-start flex-col flex-1 [&:not(:last-child)]:after:relative [&:not(:last-child)]:after:order-[-1] [&:not(:last-child)]:after:start-[50%] [&:not(:last-child)]:after:end-[50%] [&:not(:last-child)]:after:top-[calc(var(--step-icon-size)/2)] [&:not(:last-child)]:after:w-[calc((100%-var(--step-icon-size))-(var(--step-gap)))]",
variant === "circle" &&
"[&:not(:last-child)]:after:flex-1 [&:not(:last-child)]:after:ms-2 [&:not(:last-child)]:after:me-2",
"[&:not(:last-child)]:after:flex-1 [&:not(:last-child)]:after:ms-[var(--step-gap)] [&:not(:last-child)]:after:me-[var(--step-gap)]",
variant === "line" &&
"flex-col flex-1 border-t-[3px] data-[active=true]:border-blue-500",
isCompletedStep &&
"[&:not(:last-child)]:after:bg-blue-500 [&:not(:last-child)]:after:data-[invalid=true]:bg-destructive",
"flex-col flex-1 border-t-[3px] data-[active=true]:border-primary",
styles?.["horizontal-step"]
)}
data-optional={steps[index || 0]?.optional}
data-completed={isCompletedStep}
data-active={active}
data-invalid={localIsError}
data-clickable={clickable}
onClick={() => onClickStep?.(index || 0)}
onClick={() => onClickStep?.(index || 0, setStep)}
ref={ref}
>
<div
Expand Down Expand Up @@ -714,19 +750,6 @@ type StepButtonContainerProps = StepSharedProps & {
children?: React.ReactNode
}

const stepButtonVariants = cva("", {
variants: {
size: {
sm: "w-9 h-9",
md: "w-10 h-10",
lg: "w-11 h-11",
},
},
defaultVariants: {
size: "md",
},
})

const StepButtonContainer = ({
isCurrentStep,
isCompletedStep,
Expand All @@ -740,7 +763,6 @@ const StepButtonContainer = ({
isLoading: isLoadingContext,
variant,
styles,
size,
} = useStepper()

const currentStepClickable = clickable || !!onClickStep
Expand All @@ -754,15 +776,16 @@ const StepButtonContainer = ({
return (
<Button
variant="ghost"
tabIndex={currentStepClickable ? 0 : -1}
className={cn(
"stepper__step-button-container",
"rounded-full p-0 pointer-events-none",
"w-[var(--step-icon-size)] h-[var(--step-icon-size)]",
"border-2 flex rounded-full justify-center items-center",
"data-[clickable=true]:pointer-events-auto",
"data-[active=true]:bg-blue-500 data-[active=true]:border-blue-500 data-[active=true]:text-primary-foreground dark:data-[active=true]:text-primary",
"data-[current=true]:border-blue-500 data-[current=true]:bg-secondary",
"data-[invalid=true]:!bg-destructive data-[invalid=true]:!border-destructive data-[invalid=true]:!text-primary-foreground dark:data-[invalid=true]:!text-primary",
stepButtonVariants({ size }),
"data-[active=true]:bg-primary data-[active=true]:border-primary data-[active=true]:text-primary-foreground",
"data-[current=true]:border-primary data-[current=true]:bg-secondary",
"data-[invalid=true]:bg-destructive data-[invalid=true]:border-destructive data-[invalid=true]:text-destructive-foreground",
styles?.["step-button-container"]
)}
aria-current={isCurrentStep ? "step" : undefined}
Expand Down Expand Up @@ -993,4 +1016,4 @@ const StepLabel = ({
}

export { Stepper, Step, useStepper }
export type { StepProps, StepperProps, StepItem }
export type { StepProps, StepperProps, StepItem }
2 changes: 0 additions & 2 deletions web/src/components/ui/timeline-slider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import * as React from 'react';
import * as SliderPrimitive from '@radix-ui/react-slider';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function MonitoringObserverFormSubmissionsTable({

const navigateToFormSubmission = useCallback(
(submissionId: string) => {
void navigate({ to: '/responses/$submissionId', params: { submissionId }});
void navigate({ to: '/responses/form-submissions/$submissionId', params: { submissionId }});
},
[navigate]
);
Expand Down
Loading