Skip to content
This repository has been archived by the owner on Oct 26, 2021. It is now read-only.

Commit

Permalink
Merge branch 'main' into renovate/major-date-io-monorepo
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotcourant authored Mar 28, 2021
2 parents d296112 + fb741a4 commit c67772c
Show file tree
Hide file tree
Showing 15 changed files with 691 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"reselect": "4.0.0",
"resolve": "1.20.0",
"resolve-url-loader": "3.1.2",
"rrule": "^2.6.8",
"sass": "1.32.8",
"selector-action": "1.2.0",
"semver": "7.3.5",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Expenses/NewExpenseDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export interface WithConnectionPropTypes extends PropTypes {
fundingSchedules: Map<number, FundingSchedule>;
}

export interface State {
interface State {
step: NewExpenseStep;
canNextStep: boolean;
}
Expand Down
74 changes: 74 additions & 0 deletions src/components/FundingSchedules/FundingScheduleList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Button, List, ListItem, ListItemText } from "@material-ui/core";
import NewFundingScheduleDialog from "components/FundingSchedules/NewFundingScheduleDialog";
import FundingSchedule from "data/FundingSchedule";
import { Map } from 'immutable';
import React, { Component } from "react";
import { connect } from "react-redux";

export interface PropTypes {
onHide: { (): void }
}

interface WithConnectionPropTypes extends PropTypes {
fundingSchedules: Map<number, FundingSchedule>;
}


interface State {
newFundingScheduleDialogOpen: boolean;
}

export class FundingScheduleList extends Component<WithConnectionPropTypes, State> {

state = {
newFundingScheduleDialogOpen: false,
};

openNewFundingScheduleDialog = () => {
return this.setState({
newFundingScheduleDialogOpen: true,
});
};

closeFundingScheduleDialog = () => {
return this.setState({
newFundingScheduleDialogOpen: false,
});
};

render() {
const { fundingSchedules, onHide } = this.props;
return (
<div className="w-full funding-schedule-list">
<NewFundingScheduleDialog onClose={ this.closeFundingScheduleDialog }
isOpen={ this.state.newFundingScheduleDialogOpen }/>
<div className="w-full p-5">
<Button onClick={ onHide }>
Back
</Button>
<Button onClick={ this.openNewFundingScheduleDialog }>
New Funding Schedule
</Button>
</div>
<List className="w-full">
{
fundingSchedules.map(schedule => (
<ListItem key={ schedule.fundingScheduleId } button>
<ListItemText>
{ schedule.name }
</ListItemText>
</ListItem>
)).toArray()
}
</List>
</div>
)
}
}

export default connect(
state => ({
fundingSchedules: Map<number, FundingSchedule>(),
}),
{}
)(FundingScheduleList);
255 changes: 255 additions & 0 deletions src/components/FundingSchedules/NewFundingScheduleDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
import MomentUtils from "@date-io/moment";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Step,
StepContent,
StepLabel,
Stepper,
TextField
} from "@material-ui/core";
import { KeyboardDatePicker, MuiPickersUtilsProvider } from '@material-ui/pickers';
import Recurrence from "components/Recurrence/Recurrence";
import { RecurrenceList } from "components/Recurrence/RecurrenceList";
import FundingSchedule from "data/FundingSchedule";
import { Formik, FormikErrors } from "formik";
import moment from "moment";
import React, { Component, Fragment } from "react";
import { connect } from "react-redux";
import { getSelectedBankAccountId } from "shared/bankAccounts/selectors/getSelectedBankAccountId";
import request from "shared/util/request";

enum NewFundingScheduleStep {
Name,
Date,
Recurrence,
}

export interface PropTypes {
onClose: { (): void };
isOpen: boolean;
}

interface WithConnectionPropTypes extends PropTypes {
bankAccountId: number;
}

interface State {
step: NewFundingScheduleStep;
}

interface newFundingScheduleForm {
name: string;
nextOccurrence: moment.Moment;
recurrenceRule: Recurrence;
}

const initialValues: newFundingScheduleForm = {
name: '',
nextOccurrence: moment(),
recurrenceRule: new Recurrence(),
};

export class NewFundingScheduleDialog extends Component<WithConnectionPropTypes, State> {

state = {
step: NewFundingScheduleStep.Name,
};

validateInput = (values: newFundingScheduleForm): FormikErrors<any> => {
return {};
};

submit = (values: newFundingScheduleForm, { setSubmitting }) => {
const { bankAccountId } = this.props;

const newFundingSchedule = new FundingSchedule({
bankAccountId: bankAccountId,
name: values.name,
description: values.recurrenceRule.name,
nextOccurrence: values.nextOccurrence,
rule: values.recurrenceRule.ruleString(),
});

console.log(newFundingSchedule);

return request().post(`/bank_accounts/${bankAccountId}/funding_schedules`, newFundingSchedule)
.then(result => {

})
.catch(error => {

});
};


nextStep = () => {
return this.setState(prevState => ({
step: Math.min(NewFundingScheduleStep.Recurrence, prevState.step + 1),
}));
};

previousStep = () => {
return this.setState(prevState => ({
step: Math.max(NewFundingScheduleStep.Name, prevState.step - 1),
}));
};

renderActions = (isSubmitting: boolean, submitForm: { (): Promise<any> }) => {
const { onClose } = this.props;
const { step } = this.state;

const cancelButton = (
<Button color="secondary" onClick={ onClose } disabled={ isSubmitting }>
Cancel
</Button>
);

const previousButton = (
<Button color="secondary" onClick={ this.previousStep } disabled={ isSubmitting }>
Previous
</Button>
);

const nextButton = (
<Button color="primary" onClick={ this.nextStep } disabled={ isSubmitting }>
Next
</Button>
);

const submitButton = (
<Button color="primary" type="submit" disabled={ isSubmitting } onClick={ submitForm }>
Create
</Button>
);

switch (step) {
case NewFundingScheduleStep.Name:
return (
<Fragment>
{ cancelButton }
{ nextButton }
</Fragment>
);
case NewFundingScheduleStep.Recurrence:
return (
<Fragment>
{ previousButton }
{ submitButton }
</Fragment>
);
default:
return (
<Fragment>
{ previousButton }
{ nextButton }
</Fragment>
);
}
};

render() {
const { onClose, isOpen } = this.props;
const { step } = this.state;

return (
<Formik
initialValues={ initialValues }
validate={ this.validateInput }
onSubmit={ this.submit }
>
{ ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
setFieldValue,
isSubmitting,
submitForm,
}) => (
<form onSubmit={ handleSubmit }>
<MuiPickersUtilsProvider utils={ MomentUtils }>
<Dialog open={ isOpen } maxWidth="sm">
<DialogTitle>
Create a new funding schedule
</DialogTitle>
<DialogContent>
<DialogContentText>
Funding schedules let us know when you will get paid so we can automatically allocate money towards
your budgets.
</DialogContentText>
<div>
<Stepper activeStep={ step } orientation="vertical">
<Step key="What do you want to call this funding schedule?">
<StepLabel>What do you want to call this funding schedule?</StepLabel>
<StepContent>
<TextField
autoFocus
className="w-full"
disabled={ isSubmitting }
error={ touched.name && !!errors.name }
helperText={ (touched.name && errors.name) ? errors.name : null }
id="new-funding-schedule-name"
label="Name"
name="name"
onBlur={ handleBlur }
onChange={ handleChange }
value={ values.name }
/>
</StepContent>
</Step>
<Step key="When do you get paid next?">
<StepLabel>When do you get paid next?</StepLabel>
<StepContent>
<KeyboardDatePicker
fullWidth
minDate={ moment().subtract('1 day') }
name="date"
margin="normal"
id="date-picker-dialog"
label="Date"
format="MM/DD/yyyy"
value={ values.nextOccurrence }
onChange={ (value) => setFieldValue('nextOccurrence', value.startOf('day')) }
KeyboardButtonProps={ {
'aria-label': 'change date',
} }
/>
</StepContent>
</Step>
<Step key="How often do you get paid?">
<StepLabel>How often do you get paid?</StepLabel>
<StepContent>
{ (step === NewFundingScheduleStep.Recurrence || values.nextOccurrence) &&
<RecurrenceList date={ values.nextOccurrence }
onChange={ (value) => setFieldValue('recurrenceRule', value) }/>
}
</StepContent>
</Step>
</Stepper>
</div>
</DialogContent>
<DialogActions>
{ this.renderActions(isSubmitting, submitForm) }
</DialogActions>
</Dialog>
</MuiPickersUtilsProvider>
</form>
) }
</Formik>
)
}
}

export default connect(
state => ({
bankAccountId: getSelectedBankAccountId(state),
}),
{}
)(NewFundingScheduleDialog);
16 changes: 16 additions & 0 deletions src/components/Recurrence/Recurrence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { RRule } from 'rrule';

export default class Recurrence {
name: string;
rule: RRule;

constructor(recurrence?: Partial<Recurrence>) {
if (recurrence) {
Object.assign(this, recurrence);
}
}

ruleString(): string {
return this.rule.toString();
}
}
Loading

0 comments on commit c67772c

Please sign in to comment.