Skip to content

Commit

Permalink
remove stopwatch timed inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
xvvvyz committed Aug 22, 2023
1 parent 9289842 commit 3a8292c
Show file tree
Hide file tree
Showing 26 changed files with 935 additions and 1,507 deletions.
12 changes: 6 additions & 6 deletions app/(account)/_components/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ interface AlertProps {
description?: ReactNode;
isConfirming?: boolean;
isConfirmingText?: string;
isOpen: boolean;
onClose: () => void;
onConfirm?: () => void;
title?: string;
toggle: () => void;
value: boolean;
}

const Alert = ({
Expand All @@ -22,12 +22,12 @@ const Alert = ({
description,
isConfirming,
isConfirmingText,
isOpen,
onClose,
onConfirm,
title = 'Are you sure?',
toggle,
value,
}: AlertProps) => (
<Dialog className="relative z-20" onClose={toggle} open={value}>
<Dialog className="relative z-20" onClose={onClose} open={isOpen}>
<div className="fixed inset-0 bg-alpha-reverse-2 backdrop-blur-sm" />
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center">
Expand All @@ -41,7 +41,7 @@ const Alert = ({
<div className="mt-16 flex flex-col-reverse gap-4">
<Button
className="m-0 -mb-3 w-full justify-center p-0 py-3"
onClick={toggle}
onClick={onClose}
variant="link"
>
{cancelText}
Expand Down
8 changes: 4 additions & 4 deletions app/(account)/_components/sign-out-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
import IconButton from '@/(account)/_components/icon-button';
import useSupabase from '@/_hooks/use-supabase';
import { ArrowLeftOnRectangleIcon } from '@heroicons/react/24/outline';
import { useBoolean } from 'usehooks-ts';
import { useToggle } from '@uidotdev/usehooks';

const SignOutButton = () => {
const isSigningOut = useBoolean();
const [isSigningOut, toggleIsSigningOut] = useToggle(false);
const supabase = useSupabase();

return (
<IconButton
icon={<ArrowLeftOnRectangleIcon className="w-7" />}
loading={isSigningOut.value}
loading={isSigningOut}
onClick={async () => {
isSigningOut.setTrue();
toggleIsSigningOut();
await supabase.auth.signOut();
}}
spinnerClassName="w-7 h-7"
Expand Down
27 changes: 20 additions & 7 deletions app/(account)/_hooks/use-delete-alert.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import { useToggle } from '@uidotdev/usehooks';
import { useEffect, useTransition } from 'react';
import { useBoolean } from 'usehooks-ts';
import usePrevious from './use-previous';

const useDeleteAlert = () => {
const [deleteAlert, toggleDeleteAlert] = useToggle(false);
const [isConfirming, toggleIsConfirming] = useToggle(false);
const [isTransitioning, startTransition] = useTransition();
const deleteAlert = useBoolean();
const isConfirming = useBoolean();
const isTransitioningPrevious = usePrevious(isTransitioning);

useEffect(() => {
if (!isTransitioning && isTransitioningPrevious) {
deleteAlert.setFalse();
isConfirming.setFalse();
toggleDeleteAlert(false);
toggleIsConfirming(false);
}
}, [deleteAlert, isConfirming, isTransitioning, isTransitioningPrevious]);
}, [
deleteAlert,
isConfirming,
isTransitioning,
isTransitioningPrevious,
toggleDeleteAlert,
toggleIsConfirming,
]);

return { deleteAlert, isConfirming, startTransition };
return {
deleteAlert,
isConfirming,
startTransition,
toggleDeleteAlert,
toggleIsConfirming,
};
};

export default useDeleteAlert;
21 changes: 9 additions & 12 deletions app/(account)/_hooks/use-stopwatch.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import parseSeconds from '@/(account)/_utilities/parse-seconds';
import { useToggle } from '@uidotdev/usehooks';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useBoolean, useDebounce } from 'usehooks-ts';

const useStopwatch = (initialTime: string | number) => {
const [isRunning, toggleIsRunning] = useToggle(false);
const [time, setTime] = useState(+initialTime || 0);
const frameId = useRef<number | undefined>();
const isRunning = useBoolean();
const startTime = useRef<number>(0);

const update = useCallback(() => {
if (isRunning.value) {
if (isRunning) {
setTime((performance.now() - startTime.current) / 1000);
frameId.current = requestAnimationFrame(update);
}
}, [isRunning.value]);
}, [isRunning]);

useEffect(() => {
if (isRunning.value) {
if (isRunning) {
startTime.current = performance.now() - time * 1000;
frameId.current = requestAnimationFrame(update);
} else if (frameId.current) {
Expand All @@ -29,7 +29,7 @@ const useStopwatch = (initialTime: string | number) => {
};

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isRunning.value]);
}, [isRunning]);

const reset = useCallback(() => {
setTime(0);
Expand All @@ -40,21 +40,18 @@ const useStopwatch = (initialTime: string | number) => {
frameId.current = undefined;
}

isRunning.setFalse();
toggleIsRunning(false);

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return {
...parseSeconds(time),
debouncedTime: useDebounce(time, 1000),
hasTime: time !== 0,
isRunning: isRunning.value,
isRunning,
reset,
start: isRunning.setTrue,
stop: isRunning.setFalse,
time,
toggle: isRunning.toggle,
toggle: toggleIsRunning,
};
};

Expand Down
12 changes: 1 addition & 11 deletions app/(account)/_server/get-input.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import createServerComponentClient from '@/_server/create-server-component-client';
import { Database } from '@/_types/database';

const getInput = (inputId: string) =>
createServerComponentClient()
Expand All @@ -18,15 +17,6 @@ const getInput = (inputId: string) =>
.order('order', { foreignTable: 'options' })
.single();

export type GetInputData = Awaited<ReturnType<typeof getInput>>['data'] & {
options: Pick<
Database['public']['Tables']['input_options']['Row'],
'id' | 'label'
>;
subjects_for: Pick<
Database['public']['Tables']['input_subjects']['Row'],
'subject_id'
>;
};
export type GetInputData = Awaited<ReturnType<typeof getInput>>['data'];

export default getInput;
26 changes: 9 additions & 17 deletions app/(account)/_server/list-events-formatted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,16 @@ const listEventsFormatted = async (subjectId: string) => {
forceArray(event.inputs).forEach((input: any) => {
const strippedLabel = strip(input.input.label);

if (input.input.type === 'stopwatch') {
if (input.option?.label) {
const key = `${strippedLabel} timed notes (aqn)`;
const value = [input.value, input.option.label];
row[key] = row[key] ?? [];
row[key].push(value);
} else {
row[`${strippedLabel} total time (q)`] = input.value;
}
if (input.input.type === 'multi_select') {
const key = `${strippedLabel} (an)`;
row[key] = row[key] ?? [];
row[key].push(input.option.label);
} else {
if (input.input.type === 'multi_select') {
const key = `${strippedLabel} (an)`;
row[key] = row[key] ?? [];
row[key].push(input.option.label);
} else {
const type = /(duration|number)/.test(input.input.type) ? 'q' : 'n';
row[`${strippedLabel} (${type})`] = input.value ?? input.option.label;
}
const type = /(duration|number|stopwatch)/.test(input.input.type)
? 'q'
: 'n';

row[`${strippedLabel} (${type})`] = input.value ?? input.option.label;
}
});

Expand Down
3 changes: 1 addition & 2 deletions app/(account)/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ Event field types:
(q): quantitative values
(t): temporal values
(an): array of nominal value e.g ['a', 'b']
(aqn): array of arrays of quantitative and nominal values e.g [[1, 'a'], [2, 'b']]
Default event fields:
Expand All @@ -58,7 +57,7 @@ Rules for "create_vis" function:
Must use a "filter" transform when charting fields that may not have values e.g {"filter":"datum['Foo (q)']"}
Must use "isValid" when filtering nominal fields e.g {"filter":"isValid(datum['Foo (n)'])"}
Must use a "flatten" transform when charting "(an)" or "(aqn)" fields e.g {"flatten":["Foo (an)"]}
Must use a "flatten" transform when charting "(an)" fields e.g {"flatten":["Foo (an)"]}
Must use a "color" encoding on "Name (n)" when a name is not specified e.g {"color":{"field":"Name (n)"}}
Must use a "point" mark when charting "(q)" fields
Expand Down
26 changes: 3 additions & 23 deletions app/(account)/inputs/_components/input-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import Checkbox from '@/(account)/_components/checkbox';
import IconButton from '@/(account)/_components/icon-button';
import NumberInput from '@/(account)/_components/input-number';
import Select from '@/(account)/_components/select';
import Tooltip from '@/(account)/_components/tooltip';
import INPUT_LABELS from '@/(account)/_constants/constant-input-labels';
import CacheKeys from '@/(account)/_constants/enum-cache-keys';
import InputTypes from '@/(account)/_constants/enum-input-types';
Expand Down Expand Up @@ -78,9 +77,7 @@ const InputForm = ({ input, duplicateInputData, subjects }: InputFormProps) => {
const type = form.watch('type')?.id;

const hasOptions =
type === InputTypes.Select ||
type === InputTypes.MultiSelect ||
type === InputTypes.Stopwatch;
type === InputTypes.Select || type === InputTypes.MultiSelect;

return (
<form
Expand Down Expand Up @@ -259,8 +256,7 @@ const InputForm = ({ input, duplicateInputData, subjects }: InputFormProps) => {
}

case InputTypes.MultiSelect:
case InputTypes.Select:
case InputTypes.Stopwatch: {
case InputTypes.Select: {
form.setValue('settings', {
isCreatable: false,
});
Expand All @@ -282,23 +278,7 @@ const InputForm = ({ input, duplicateInputData, subjects }: InputFormProps) => {
{hasOptions && (
<>
<fieldset className="group">
<div className="flex justify-between">
<span className="label">
{type === InputTypes.Stopwatch ? 'Timed notes' : 'Options'}
</span>
{type === InputTypes.Stopwatch && (
<Tooltip
className="relative -top-1 -mr-[0.15rem]"
id="options-tip"
tip={
<>
If you add options or allow options to be created, you can
record notes that are associated with a timestamp.
</>
}
/>
)}
</div>
<span className="label">Options</span>
<div className="space-y-2">
{!!optionsArray.fields.length && (
<ul className="flex flex-col gap-2">
Expand Down
20 changes: 14 additions & 6 deletions app/(account)/inputs/_components/input-list-item-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,38 @@ interface InputListItemMenuProps {
const InputListItemMenu = ({ inputId }: InputListItemMenuProps) => {
const router = useRouter();
const supabase = useSupabase();
const { deleteAlert, isConfirming, startTransition } = useDeleteAlert();

const {
deleteAlert,
isConfirming,
startTransition,
toggleDeleteAlert,
toggleIsConfirming,
} = useDeleteAlert();

return (
<>
<Alert
confirmText="Delete input"
isConfirming={isConfirming.value}
isConfirming={isConfirming}
isConfirmingText="Deleting input…"
isOpen={deleteAlert}
onClose={toggleDeleteAlert}
onConfirm={async () => {
isConfirming.setTrue();
toggleIsConfirming(true);

const { error } = await supabase
.from('inputs')
.update({ deleted: true })
.eq('id', inputId);

if (error) {
isConfirming.setFalse();
toggleIsConfirming(false);
alert(error.message);
} else {
startTransition(router.refresh);
}
}}
{...deleteAlert}
/>
<Menu className="shrink-0">
<Menu.Button className="h-full border-l border-alpha-1 px-4 group-first:rounded-tr group-last:rounded-br">
Expand All @@ -53,7 +61,7 @@ const InputListItemMenu = ({ inputId }: InputListItemMenuProps) => {
<DocumentDuplicateIcon className="w-5 text-fg-4" />
Duplicate input
</Menu.Item>
<Menu.Item onClick={deleteAlert.setTrue}>
<Menu.Item onClick={() => toggleDeleteAlert(true)}>
<TrashIcon className="w-5 text-fg-4" />
Delete input
</Menu.Item>
Expand Down
10 changes: 5 additions & 5 deletions app/(account)/subjects/[subjectId]/_components/disclosure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import DirtyHtml from '@/(account)/_components/dirty-html';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import { useToggle } from '@uidotdev/usehooks';
import { twMerge } from 'tailwind-merge';
import { useBoolean } from 'usehooks-ts';

interface DisclosureProps {
children: string;
Expand All @@ -12,25 +12,25 @@ interface DisclosureProps {
}

const Disclosure = ({ children, className, disabled }: DisclosureProps) => {
const disclosure = useBoolean(disabled);
const [disclosure, toggleDisclosure] = useToggle(disabled);

return (
<div
className={twMerge(
'group relative -mb-8 -mt-9 max-h-24 overflow-hidden px-4 py-8 after:absolute after:bottom-0 after:left-0 after:right-0 after:top-0 after:bg-gradient-to-b after:from-transparent after:via-[hsla(40,5%,13%,0.75)] after:to-[hsl(40,5%,13%)] sm:px-8',
disclosure.value && 'max-h-full after:hidden',
disclosure && 'max-h-full after:hidden',
disabled ? 'cursor-default' : 'select-none',
className,
)}
onClick={(e) => {
if (!disabled && (e.target as HTMLElement).localName !== 'a') {
disclosure.toggle();
toggleDisclosure();
}
}}
role="button"
>
<DirtyHtml>{children}</DirtyHtml>
{!disclosure.value && (
{!disclosure && (
<ChevronDownIcon className="absolute bottom-4 left-1/2 z-10 w-7 -translate-x-1/2 text-fg-3 transition-colors group-hover:text-fg-2" />
)}
</div>
Expand Down
Loading

0 comments on commit 3a8292c

Please sign in to comment.