Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Adoption & Interest pages
  • Loading branch information
RoyEJohnson committed Aug 6, 2025
commit f3e67ad16fcf02ec29bacd5766cf4bdb6a14de1c
2 changes: 1 addition & 1 deletion src/app/components/book-checkbox/book-checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './book-checkbox.scss';

export default function BookCheckbox({book, name, checked, toggle, disabled}: {
book: SalesforceBook;
name: string;
name?: string;
checked: boolean;
toggle: (b: SalesforceBook) => void;
disabled?: boolean;
Expand Down
6 changes: 3 additions & 3 deletions src/app/components/book-selector/book-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function Subject({
}: {
subject: string;
books: SalesforceBook[];
name: string;
name?: string;
selectedBooks: SalesforceBook[];
toggleBook: (b: SalesforceBook) => void;
limitReached: boolean;
Expand Down Expand Up @@ -64,12 +64,12 @@ const defaultIncludeFilter = () => true;

type PropsFromOutside = {
prompt: string;
name: string;
name?: string;
selectedBooks: SalesforceBook[];
toggleBook: (b: SalesforceBook) => void;
limit?: number;
additionalInstructions?: string;
includeFilter?: () => boolean;
includeFilter?: (b: SalesforceBook) => boolean;
};

type Books = Parameters<typeof salesforceTitles>[0]
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/form-input/form-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export default function FormInput({
inputProps,
suggestions
}: {
label: string;
label?: string;
longLabel?: string;
inputProps: InputProps;
suggestions?: string[];
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/multi-page-form/multi-page-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ function PageCount() {

type MultiPageFormProps = {
children: React.ReactNode[];
validatePage?: (p: unknown) => boolean;
onPageChange?: (p: unknown) => boolean;
validatePage?: (p: number) => boolean;
onPageChange?: (p: number) => void;
onSubmit: (form: HTMLFormElement) => void;
submitting: boolean;
// onSubmit is redefined above to be simpler
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/multi-page-form/pages-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import buildContext from '~/components/jsx-helpers/build-context';

function useContextValue({pages, validatePage, onPageChange}: {
pages: number;
validatePage: (p: unknown) => boolean;
onPageChange: (p: unknown) => void;
validatePage: (p: number) => boolean;
onPageChange: (p: number) => void;
}) {
const [validatedPages, setValidatedPages] = useState({});
const activeRef = useRef<HTMLDivElement>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ import {useAfterSubmit} from '~/components/book-selector/after-form-submit';
import BookSelector, {
useSelectedBooks
} from '~/components/book-selector/book-selector';
import {SalesforceBook} from '~/helpers/books';
import HowUsing from './how-using/how-using';
import useSalesforceContext from '~/contexts/salesforce';
import useFormTarget from '~/components/form-target/form-target';
import TrackingParameters from '~/components/tracking-parameters/tracking-parameters';
import {useIntl} from 'react-intl';
import './adoption.scss';

function BookSelectorPage({selectedBooksRef, year}) {
function BookSelectorPage({selectedBooksRef, year}: {
selectedBooksRef: React.MutableRefObject<SalesforceBook[]>;
year?: string;
}) {
const [selectedBooks, toggleBook] = useSelectedBooks();
const bookList = React.useMemo(
() => selectedBooks.map((b) => b.value.replace(/ *\[.*/, '')).join('; '),
Expand All @@ -27,7 +31,7 @@ function BookSelectorPage({selectedBooksRef, year}) {
const {formatMessage} = useIntl();
const instructions = formatMessage({id: 'adoption.instructions'});
const includeFilter = React.useCallback(
(b) => !b.comingSoon,
(b: SalesforceBook) => !b.comingSoon,
[]
);

Expand All @@ -36,10 +40,9 @@ function BookSelectorPage({selectedBooksRef, year}) {
<React.Fragment>
<BookSelector
prompt={formatMessage({id: 'adoption.book-prompt'})}
required
selectedBooks={selectedBooks}
toggleBook={toggleBook}
limit="5"
limit={5}
additionalInstructions={instructions}
includeFilter={includeFilter}
/>
Expand All @@ -53,39 +56,37 @@ function BookSelectorPage({selectedBooksRef, year}) {
);
}

function FacultyForm({position, onPageChange}) {
const selectedBooksRef = useRef();
function FacultyForm({position, onPageChange}: {
position: string;
onPageChange: (page: number) => void;
}) {
const selectedBooksRef = useRef<SalesforceBook[]>([]);
const afterSubmit = useAfterSubmit(selectedBooksRef);
const {onSubmit, submitting, FormTarget} = useFormTarget(afterSubmit);
const {adoptionUrl} = useSalesforceContext();
const validatePage = React.useCallback(
(page) => {
if (page === 1 && position === 'Student') {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Student processing can't get here

return false;
}
(page: number) => {
if (page === 2 && selectedBooksRef.current.length < 1) {
return false;
}
return true;
},
[position]
[]
);
const doSubmit = React.useCallback(
(form) => {
if (selectedBooksRef.current?.length > 0) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't get here with no selected books.

form.submit();
onSubmit();
}
(form: HTMLFormElement) => {
form.submit();
onSubmit();
},
[onSubmit]
);
const {search} = useLocation();
const selectedYear = new window.URLSearchParams(search).get('year') ?? undefined;
const [copyOfYear, setCopyOfYear] = React.useState();
const [copyOfYear, setCopyOfYear] = React.useState<string>();

return (
<React.Fragment>
<FormTarget submitting={submitting} />
<FormTarget />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

submitting isn't handled with a parameter anymore.

<MultiPageForm
validatePage={validatePage} action={adoptionUrl}
onPageChange={onPageChange} onSubmit={doSubmit}
Expand All @@ -96,7 +97,7 @@ function FacultyForm({position, onPageChange}) {
<input type="hidden" name="position" value={position} />
<input type="hidden" name="role" value="Instructor" />
<input type="hidden" name="lead_source" value="Adoption Form" />
<input type="hidden" name="process_adoptions" value={true} />
<input type="hidden" name="process_adoptions" value="true" />
<div className="year-selector-container">
<YearSelector selectedYear={selectedYear} onValueUpdate={setCopyOfYear} />
</div>
Expand All @@ -111,11 +112,11 @@ function FacultyForm({position, onPageChange}) {
export default function AdoptionForm() {
const [selectedRole, setSelectedRole] = useState('');
const [hideRoleSelector, setHideRoleSelector] = useState(false);
const ref = useRef();
const ref = useRef<HTMLDivElement>(null);
const onPageChange = React.useCallback(
(page) => {
(page: number) => {
setHideRoleSelector(page > 1);
ref.current.scrollIntoView();
ref.current?.scrollIntoView();
},
[]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import React from 'react';
import FormInput from '~/components/form-input/form-input';
import FormSelect from '~/components/form-select/form-select';
import {adoptionOptions} from '~/contexts/salesforce';
import {SalesforceBook} from '~/helpers/books';
import {FormattedMessage, useIntl} from 'react-intl';
import './how-using.scss';

function HowManyStudents({book, dispatch}) {
function HowManyStudents({book, dispatch}: {
book: SalesforceBook;
dispatch: React.Dispatch<object>;
}) {
const updateBookValue = React.useCallback(
({target: {value}}) => {
({target: {value}}: React.ChangeEvent<HTMLInputElement>) => {
dispatch({[book.value]: value});
},
[book, dispatch]
Expand Down Expand Up @@ -36,9 +40,12 @@ function HowManyStudents({book, dispatch}) {
);
}

function HowUsingBook({book, dispatch}) {
function HowUsingBook({book, dispatch}: {
book: SalesforceBook;
dispatch: React.Dispatch<object>;
}) {
const updateBookValue = React.useCallback(
(value) => dispatch({[book.value]: value}),
(value: string) => dispatch({[book.value]: value}),
[book, dispatch]
);
const {formatMessage} = useIntl();
Expand All @@ -48,18 +55,16 @@ function HowUsingBook({book, dispatch}) {
outside: formatMessage({id: 'how-using.outside'}),
self: formatMessage({id: 'how-using.self'})
};

adoptionOptions.forEach((opt) => {
opt.label = adoptionTexts[opt.key];
});
const adoptionOptionsWithLabels = adoptionOptions.map((opt) => ({...opt, label: adoptionTexts[opt.key]}));

return (
<FormSelect
name={`hufs_${book.text}`}
label={formatMessage(
{id: 'how-using.how-using'},
{title: book.text}
)}
options={adoptionOptions}
options={adoptionOptionsWithLabels}
selectAttributes={{
name: `hu_${book.text}`,
placeholder: formatMessage({id: 'selector.select-one'}),
Expand All @@ -70,11 +75,14 @@ function HowUsingBook({book, dispatch}) {
);
}

function reducer(state, action) {
function reducer(state: Record<string, unknown>, action: object) {
return {...state, ...action};
}

export default function HowUsing({selectedBooks, year}) {
export default function HowUsing({selectedBooks, year}: {
selectedBooks: SalesforceBook[];
year?: string;
}) {
const [bookData, dispatch] = React.useReducer(reducer, {});
const [useData, udDispatch] = React.useReducer(reducer, {});
const json = React.useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import FormCheckboxgroup from '~/components/form-checkboxgroup/form-checkboxgrou
import TrackingParameters from '~/components/tracking-parameters/tracking-parameters';
import {useIntl} from 'react-intl';
import './interest.scss';
import { SalesforceBook } from '~/helpers/books';

function useBundledValues() {
const [bundledValues, setBundledValues] = useState('');
const onChange = React.useCallback(
(values) => setBundledValues(values.join('; ')),
(values: unknown[]) => setBundledValues(values.join('; ')),
[]
);

Expand Down Expand Up @@ -54,6 +55,7 @@ function HowDidYouHear() {
return (
<React.Fragment>
<FormCheckboxgroup
name='how_did_you_hear'
longLabel={formatMessage({id: 'interest.how'})}
instructions={formatMessage({id: 'interest.select-instruction'})}
options={options}
Expand All @@ -64,7 +66,9 @@ function HowDidYouHear() {
);
}

function BookSelectorPage({ selectedBooksRef }) {
function BookSelectorPage({ selectedBooksRef }: {
selectedBooksRef: React.MutableRefObject<unknown>;
}) {
const [selectedBooks, toggleBook] = useSelectedBooks();
const bookList = selectedBooks.map((b) => b.value).join('; ');
const {formatMessage} = useIntl();
Expand All @@ -75,10 +79,9 @@ function BookSelectorPage({ selectedBooksRef }) {
<div className="page-2">
<BookSelector
prompt={formatMessage({id: 'interest.books-prompt'})}
required
selectedBooks={selectedBooks}
toggleBook={toggleBook}
limit="5"
limit={5}
/>
<FormInput
longLabel={formatMessage({id: 'interest.students-prompt'})}
Expand All @@ -96,29 +99,31 @@ function BookSelectorPage({ selectedBooksRef }) {
);
}

function FacultyForm({ position, onPageChange, role }) {
const selectedBooksRef = useRef();
function FacultyForm({ position, onPageChange, role }: {
position: string;
onPageChange?: (p: number) => void;
role: string;
}) {
const selectedBooksRef = useRef<SalesforceBook[]>([]);
const afterSubmit = useAfterSubmit(selectedBooksRef);
const { onSubmit, submitting, FormTarget } = useFormTarget(afterSubmit);
const { interestUrl } = useSalesforceContext();

function validatePage(page) {
function validatePage(page: number) {
return Boolean(page !== 1 || position !== 'Student');
}

const doSubmit = React.useCallback(
(form) => {
if (selectedBooksRef.current?.length > 0) {
form.submit();
onSubmit();
}
(form: HTMLFormElement) => {
form.submit();
onSubmit();
},
[onSubmit]
);

return (
<React.Fragment>
<FormTarget submitting={submitting} />
<FormTarget />
<MultiPageForm
validatePage={validatePage}
action={interestUrl}
Expand Down Expand Up @@ -147,10 +152,10 @@ function FacultyForm({ position, onPageChange, role }) {
export function InterestForm({ role = 'Instructor' }) {
const [selectedRole, setSelectedRole] = useState('');
const [hideRoleSelector, setHideRoleSelector] = useState(false);
const ref = useRef();
const onPageChange = React.useCallback((page) => {
const ref = useRef<HTMLDivElement>(null);
const onPageChange = React.useCallback((page: number) => {
setHideRoleSelector(page > 1);
ref.current.scrollIntoView();
ref.current?.scrollIntoView();
}, []);

return (
Expand Down