Skip to content

Commit

Permalink
botw-schedule - temp save botw bills in local storage
Browse files Browse the repository at this point in the history
  • Loading branch information
dcordz committed Nov 15, 2024
1 parent c0d0ad8 commit 9fefe6e
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 97 deletions.
5 changes: 4 additions & 1 deletion app/frontend/components/bill/creator/BillCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { router, usePage } from "@inertiajs/react";
import { ISubmitValues } from "app/frontend/components/admin/types";
import { useAxiosPost } from "app/frontend/hooks/useAxios";

import BillCreatorFormikForm from "app/frontend/components/bill/creator/BillCreatorFormikForm";
import { useNewBillInitialValues } from "app/frontend/components/bill/creator/hooks/useNewBillInitialValues";
import { TempBillStorage } from "app/frontend/components/bill/creator/TempBillStorage";
import { useLocale } from "app/frontend/hooks/useLocales";
import BillCreatorFormikForm from "app/frontend/components/bill/creator/BillCreatorFormikForm";

const VALIDATION_SCHEMA = yup.object().shape({
externalId: yup.string().required(),
Expand Down Expand Up @@ -206,6 +207,8 @@ const BillCreator: React.FC<IProps> = ({ setCreatorDirty }) => {

await handleCreateLegislatorVotes(values, result.id, setSubmitting).catch(handleError);

TempBillStorage.remove();

router.visit(ROUTES.billOfTheWeekCreatorEdit(result.id));
}
})
Expand Down
173 changes: 103 additions & 70 deletions app/frontend/components/bill/creator/BillCreatorFormikForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ import BillComponent from "app/frontend/components/bill/BillComponent";

import { usePage } from "@inertiajs/react";
import { ISubmitValues } from "app/frontend/components/admin/types";
import { forwardRef, useEffect } from "react";
import { TempBillStorage } from "app/frontend/components/bill/creator/TempBillStorage";
import { logDev } from "app/frontend/sway_utils";
import { forwardRef, useEffect, useMemo, useState } from "react";

interface IProps {
setCreatorDirty: React.Dispatch<React.SetStateAction<boolean>>;
}

const BillCreatorFormikForm = forwardRef(({ setCreatorDirty }: IProps, summaryRef: React.Ref<string>) => {
const BillCreatorFormikForm = forwardRef(({ setCreatorDirty }: IProps, _summaryRef: React.ForwardedRef<string>) => {
const summaryRef = _summaryRef as React.MutableRefObject<string>;
const formik = useFormikContext<ISubmitValues>();

const bill = usePage().props.bill as sway.IBill;
Expand All @@ -27,9 +30,106 @@ const BillCreatorFormikForm = forwardRef(({ setCreatorDirty }: IProps, summaryRe
setCreatorDirty(formik.dirty);
}, [setCreatorDirty, formik.dirty]);

const [countdown, setCountdown] = useState<number>(3);

useEffect(() => {
setCountdown(3);
const timeout = window.setTimeout(() => {
logDev("TIMEOUT - STORE BILL");
TempBillStorage.set({
...formik.values,
summary: summaryRef.current || "",
});
}, 5000);

const interval = window.setInterval(() => {
setCountdown((current) => current - 1);
}, 1000);

return () => {
window.clearTimeout(timeout);
window.clearInterval(interval);
};
}, [formik.values, summaryRef]);

const positions = useMemo(
() =>
formik.values.organizationsSupport
.map(
(p) =>
({
support: Support.For,
summary: p.summary,
organization: {
id: p.value,
name: p.label,
iconPath: p.iconPath,
},
}) as sway.IOrganizationPosition,
)
.concat(
formik.values.organizationsOppose.map(
(p) =>
({
support: Support.Against,
summary: p.summary,
organization: {
id: p.value,
name: p.label,
iconPath: p.iconPath,
},
}) as sway.IOrganizationPosition,
),
),
[formik.values.organizationsSupport, formik.values.organizationsOppose],
);

const legislatorVotes = useMemo(
() =>
formik.values.supporters
.map(
(s) =>
({
legislatorId: s.value,
support: Support.For,
billId: bill.id || -1,
}) as sway.ILegislatorVote,
)
.concat(
formik.values.opposers.map(
(s) =>
({
legislatorId: s.value,
support: Support.Against,
billId: bill.id || -1,
}) as sway.ILegislatorVote,
),
)
.concat(
formik.values.abstainers.map(
(s) =>
({
legislatorId: s.value,
support: Support.Abstain,
billId: bill.id || -1,
}) as sway.ILegislatorVote,
),
)
.flat(),
[formik.values.supporters, formik.values.opposers, formik.values.abstainers, bill.id],
);

const sponsor = useMemo(
() => legislators.find((l) => l.id === (formik.values.legislator?.value as number)) as sway.ILegislator,
[formik.values.legislator?.value, legislators],
);

return (
<>
<FormikForm>
<div className={countdown >= 0 && countdown <= 3 ? "visible my-2" : "invisible my-2"}>
Store Temporary Bill in: {countdown}
</div>
<BillCreatorFields ref={summaryRef} />
<div className="mx-auto text-center p-5">
<div className="row align-items-center">
Expand All @@ -55,74 +155,7 @@ const BillCreatorFormikForm = forwardRef(({ setCreatorDirty }: IProps, summaryRe
</FormikForm>
<hr />
<div className="bolder h2">Bill of the Week Preview</div>
<BillComponent
bill={{
...formik.values,
// @ts-expect-error - Property 'current' does not exist on type '((instance: string | null) => void) | RefObject<string>'.
summary: summaryRef?.current || "",
legislatorId: formik.values.legislator?.value as number,
}}
positions={formik.values.organizationsSupport
.map(
(p) =>
({
support: Support.For,
summary: p.summary,
organization: {
id: p.value,
name: p.label,
iconPath: p.iconPath,
},
}) as sway.IOrganizationPosition,
)
.concat(
formik.values.organizationsOppose.map(
(p) =>
({
support: Support.Against,
summary: p.summary,
organization: {
id: p.value,
name: p.label,
iconPath: p.iconPath,
},
}) as sway.IOrganizationPosition,
),
)}
sponsor={
legislators.find((l) => l.id === (formik.values.legislator?.value as number)) as sway.ILegislator
}
legislatorVotes={formik.values.supporters
.map(
(s) =>
({
legislatorId: s.value,
support: Support.For,
billId: bill.id || -1,
}) as sway.ILegislatorVote,
)
.concat(
formik.values.opposers.map(
(s) =>
({
legislatorId: s.value,
support: Support.Against,
billId: bill.id || -1,
}) as sway.ILegislatorVote,
),
)
.concat(
formik.values.abstainers.map(
(s) =>
({
legislatorId: s.value,
support: Support.Abstain,
billId: bill.id || -1,
}) as sway.ILegislatorVote,
),
)
.flat()}
/>
<BillComponent bill={bill} positions={positions} sponsor={sponsor} legislatorVotes={legislatorVotes} />
</>
);
});
Expand Down
22 changes: 13 additions & 9 deletions app/frontend/components/bill/creator/BillOfTheWeekCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { ROUTES } from "app/frontend/sway_constants";
import { logDev, REACT_SELECT_STYLES } from "app/frontend/sway_utils";
import { lazy, Suspense, useCallback, useMemo, useState } from "react";
import { Button, ButtonGroup, Form, Nav, Tab } from "react-bootstrap";
import { Button, ButtonGroup, Form, Nav, ProgressBar, Tab } from "react-bootstrap";
import Select, { SingleValue } from "react-select";
import { ISelectOption, sway } from "sway";

Expand All @@ -15,11 +15,11 @@ import FullScreenLoading from "app/frontend/components/dialogs/FullScreenLoading
import SwayLogo from "app/frontend/components/SwayLogo";
import LocaleSelector from "app/frontend/components/user/LocaleSelector";

import BillCreator from "app/frontend/components/bill/creator/BillCreator";
import { ETab } from "app/frontend/components/bill/creator/constants";
import { TempBillStorage } from "app/frontend/components/bill/creator/TempBillStorage";
import { useSearchParams } from "app/frontend/hooks/useSearchParams";
import CenteredLoading from "app/frontend/components/dialogs/CenteredLoading";

const BillCreator = lazy(() => import("app/frontend/components/bill/creator/BillCreator"));
const BillSchedule = lazy(() => import("app/frontend/components/bill/creator/BillSchedule"));

interface IProps {
Expand Down Expand Up @@ -103,7 +103,7 @@ const BillOfTheWeekCreator_: React.FC<IProps> = ({ bills, bill, user, tabKey = E
<div className="row align-items-center">
<div className="col">
<Form.Label className="my-0 bold">Sway Locale</Form.Label>
<LocaleSelector />
<LocaleSelector callback={TempBillStorage.remove} />
</div>
</div>

Expand All @@ -118,8 +118,10 @@ const BillOfTheWeekCreator_: React.FC<IProps> = ({ bills, bill, user, tabKey = E
styles={REACT_SELECT_STYLES}
menuPortalTarget={document.body}
menuPosition="fixed"
// @ts-expect-error - Types of parameters 'newParams' and 'actionMeta' are incompatible.
onChange={handleChangeBill}
onChange={(o) => {
handleChangeBill(o);
TempBillStorage.remove();
}}
/>
</div>
</div>
Expand Down Expand Up @@ -154,12 +156,14 @@ const BillOfTheWeekCreator_: React.FC<IProps> = ({ bills, bill, user, tabKey = E
</ButtonGroup>
</div>
</Nav>
<Tab.Content>
<Tab.Content className="mt-3">
<Tab.Pane title="Bill Creator" eventKey={ETab.Creator}>
<BillCreator setCreatorDirty={setCreatorDirty} />
<Suspense fallback={<ProgressBar animated striped now={100} />}>
{tabKey === ETab.Creator && <BillCreator setCreatorDirty={setCreatorDirty} />}
</Suspense>
</Tab.Pane>
<Tab.Pane title="Schedule" eventKey={ETab.Schedule}>
<Suspense fallback={<CenteredLoading />}>
<Suspense fallback={<ProgressBar animated striped now={100} />}>
<BillSchedule
params={params}
selectedBill={selectedBill}
Expand Down
23 changes: 23 additions & 0 deletions app/frontend/components/bill/creator/TempBillStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { notify, SWAY_STORAGE } from "app/frontend/sway_utils";

export const TempBillStorage = {
set: (values: Record<string, any>) => {
localStorage.setItem(SWAY_STORAGE.Local.BillOfTheWeek.Temp, JSON.stringify(values));
notify({ level: "success", title: "Temporary Bill Stored", duration: 1000 });
},
remove: () => {
localStorage.removeItem(SWAY_STORAGE.Local.BillOfTheWeek.Temp);
notify({ level: "warning", title: "Temporary Bill Removed", duration: 1000 });
},
get: () => {
const stored = localStorage.getItem(SWAY_STORAGE.Local.BillOfTheWeek.Temp);
if (stored) {
window.setTimeout(() => {
notify({ level: "info", title: "Loaded Bill From Temp Storage", duration: 1000 });
}, 100);
return JSON.parse(stored);
} else {
return null;
}
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ISelectOption, sway } from "sway";

import { usePage } from "@inertiajs/react";
import { ISubmitValues } from "app/frontend/components/admin/types";
import { TempBillStorage } from "app/frontend/components/bill/creator/TempBillStorage";
import { useLocale } from "app/frontend/hooks/useLocales";

export const useNewBillInitialValues = () => {
Expand Down Expand Up @@ -72,9 +73,12 @@ export const useNewBillInitialValues = () => {
return { supporters: s, opposers: o, abstainers: a };
}, []);

return useMemo(
() =>
({
return useMemo(() => {
const stored = TempBillStorage.get();
if (stored) {
return stored;
} else {
return {
...initialBill,
legislator: legislatorToSelectOption(legislators.find((l) => l.id === initialBill.legislatorId)),

Expand All @@ -98,9 +102,9 @@ export const useNewBillInitialValues = () => {
summary: p.summary,
iconPath: p.organization.iconPath,
})),
}) as ISubmitValues,
[initialBill, legislators, organizationPositions, supporters, opposers, abstainers],
);
} as ISubmitValues;
}
}, [initialBill, legislators, organizationPositions, supporters, opposers, abstainers]);
};

const legislatorToSelectOption = (legislator?: sway.ILegislator | null) => {
Expand Down
6 changes: 4 additions & 2 deletions app/frontend/components/user/LocaleSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { REACT_SELECT_STYLES } from "../../sway_utils";

interface IProps {
containerStyle?: React.CSSProperties;
callback?: () => void;
}

const toSelectOption = (l: sway.ISwayLocale): ISelectOption => ({ label: toFormattedLocaleName(l.name), value: l.id });

const LocaleSelector: React.FC<IProps> = () => {
const LocaleSelector: React.FC<IProps> = ({ callback }) => {
const { options } = useLocales();
const [locale, getLocale] = useLocale();

Expand All @@ -31,9 +32,10 @@ const LocaleSelector: React.FC<IProps> = () => {
(o: SingleValue<ISelectOption>) => {
if (o) {
getLocale(Number(o.value));
callback?.();
}
},
[getLocale],
[getLocale, callback],
);

return (
Expand Down
Loading

0 comments on commit 9fefe6e

Please sign in to comment.