Skip to content

Commit

Permalink
botw-schedule - prompt before changing to scheduler when creator is d…
Browse files Browse the repository at this point in the history
…irty
  • Loading branch information
dcordz committed Nov 14, 2024
1 parent 9e213f8 commit cc4b547
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 118 deletions.
124 changes: 13 additions & 111 deletions app/frontend/components/bill/creator/BillCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { ROUTES, Support } from "app/frontend/sway_constants";
import { getId, getSelectValue, isCongressLocale, logDev, handleError, notify } from "app/frontend/sway_utils";
import { Formik, Form as FormikForm } from "formik";
import { getId, getSelectValue, handleError, isCongressLocale, logDev, notify } from "app/frontend/sway_utils";
import { Formik } from "formik";
import { useCallback, useRef } from "react";
import { Button } from "react-bootstrap";
import { FiSave } from "react-icons/fi";
import { sway } from "sway";
import * as yup from "yup";

import { router, usePage } from "@inertiajs/react";
import BillCreatorFields from "app/frontend/components/admin/creator/BillCreatorFields";
import { ISubmitValues } from "app/frontend/components/admin/types";
import SwaySpinner from "app/frontend/components/SwaySpinner";
import { useAxiosPost } from "app/frontend/hooks/useAxios";

import BillComponent from "app/frontend/components/bill/BillComponent";

import { useNewBillInitialValues } from "app/frontend/components/bill/creator/hooks/useNewBillInitialValues";
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 All @@ -36,7 +31,11 @@ const VALIDATION_SCHEMA = yup.object().shape({
senateRollCallVoteNumber: yup.number().nullable().notRequired(),
});

const BillCreator = () => {
interface IProps {
setCreatorDirty: React.Dispatch<React.SetStateAction<boolean>>;
}

const BillCreator: React.FC<IProps> = ({ setCreatorDirty }) => {
const summaryRef = useRef<string>("");
const [locale] = useLocale();
const bill = usePage().props.bill as sway.IBill;
Expand Down Expand Up @@ -230,109 +229,12 @@ const BillCreator = () => {
validationSchema={VALIDATION_SCHEMA}
onSubmit={handleSubmit}
enableReinitialize={true}
onReset={() => logDev("RESET FORMIK")}
>
{(formik) => {
return (
<>
<FormikForm>
<BillCreatorFields ref={summaryRef} />
<div className="mx-auto text-center p-5">
<div className="row align-items-center">
<div className="col text-center">
<Button
disabled={formik.isSubmitting}
variant="primary"
size="lg"
type="submit"
className="p-5 w-50"
>
<FiSave />
&nbsp;Save
</Button>
</div>
</div>
<div className="row align-items-center mt-3">
<div className="col text-center">
<SwaySpinner isHidden={!formik.isSubmitting} />
</div>
</div>
</div>
</FormikForm>
<hr />
<div className="bolder h2">Bill of the Week Preview</div>
<BillComponent
bill={{
...formik.values,
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()}
/>
</>
);
onReset={() => {
logDev("RESET FORMIK");
setCreatorDirty(false);
}}
>
<BillCreatorFormikForm ref={summaryRef} setCreatorDirty={setCreatorDirty} />
</Formik>
);
};
Expand Down
130 changes: 130 additions & 0 deletions app/frontend/components/bill/creator/BillCreatorFormikForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { Support } from "app/frontend/sway_constants";
import { Form as FormikForm, useFormikContext } from "formik";
import { Button } from "react-bootstrap";
import { FiSave } from "react-icons/fi";
import { sway } from "sway";

import BillCreatorFields from "app/frontend/components/admin/creator/BillCreatorFields";
import SwaySpinner from "app/frontend/components/SwaySpinner";

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";

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

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

const bill = usePage().props.bill as sway.IBill;
const legislators = usePage().props.legislators as sway.ILegislator[];

useEffect(() => {
setCreatorDirty(formik.dirty);
}, [setCreatorDirty, formik.dirty]);

return (
<>
<FormikForm>
<BillCreatorFields ref={summaryRef} />
<div className="mx-auto text-center p-5">
<div className="row align-items-center">
<div className="col text-center">
<Button
disabled={formik.isSubmitting}
variant="primary"
size="lg"
type="submit"
className="p-5 w-50"
>
<FiSave />
&nbsp;Save
</Button>
</div>
</div>
<div className="row align-items-center mt-3">
<div className="col text-center">
<SwaySpinner isHidden={!formik.isSubmitting} />
</div>
</div>
</div>
</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()}
/>
</>
);
});

export default BillCreatorFormikForm;
27 changes: 20 additions & 7 deletions app/frontend/components/bill/creator/BillOfTheWeekCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/** @format */
import { ROUTES } from "app/frontend/sway_constants";
import { logDev, REACT_SELECT_STYLES } from "app/frontend/sway_utils";
import { useCallback, useMemo } from "react";
import { useCallback, useMemo, useState } from "react";
import { Button, ButtonGroup, Form, Nav, Tab } from "react-bootstrap";
import Select, { SingleValue } from "react-select";
import { ISelectOption, sway } from "sway";
Expand Down Expand Up @@ -39,6 +39,7 @@ const BillOfTheWeekCreator_: React.FC<IProps> = ({ bills, bill, user, tabKey = E
const { isAdmin } = user;

const isLoading = useMemo(() => false, []);
const [isCreatorDirty, setCreatorDirty] = useState<boolean>(false);

const selectedBill = useMemo(
() =>
Expand Down Expand Up @@ -69,11 +70,23 @@ const BillOfTheWeekCreator_: React.FC<IProps> = ({ bills, bill, user, tabKey = E
}
}, []);

const handleChangeTab = useCallback((newTabKey: string | null) => {
if (!newTabKey) return;

params.add("tabKey", newTabKey);
}, []);
const handleChangeTab = useCallback(
(newTabKey: string | null) => {
if (!newTabKey) return;

if (isCreatorDirty && newTabKey === ETab.Schedule) {
const isConfirmed = window.confirm(
"Switching to the scheduler will remove all unsaved data from the Bill Creator. Continue?",
);
if (isConfirmed) {
params.add("tabKey", newTabKey);
}
} else {
params.add("tabKey", newTabKey);
}
},
[isCreatorDirty],
);

if (!isAdmin || !locale) {
logDev("BillOfTheWeekCreator - no admin OR no locale - render null");
Expand Down Expand Up @@ -141,7 +154,7 @@ const BillOfTheWeekCreator_: React.FC<IProps> = ({ bills, bill, user, tabKey = E
</Nav>
<Tab.Content>
<Tab.Pane title="Bill Creator" eventKey={ETab.Creator}>
<BillCreator />
<BillCreator setCreatorDirty={setCreatorDirty} />
</Tab.Pane>
<Tab.Pane title="Schedule" eventKey={ETab.Schedule}>
<BillSchedule params={params} selectedBill={selectedBill} setSelectedBill={handleChangeBill} />
Expand Down

0 comments on commit cc4b547

Please sign in to comment.