This repository has been archived by the owner on Oct 26, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into renovate/major-date-io-monorepo
- Loading branch information
Showing
15 changed files
with
691 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
255
src/components/FundingSchedules/NewFundingScheduleDialog.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
Oops, something went wrong.