feat: Replace Redirect with withRouter

This commit is contained in:
Alexander Polynomdivision 2018-09-19 20:30:42 +02:00
parent 286927663a
commit 1c15c6653f
7 changed files with 203 additions and 221 deletions

View File

@ -52,18 +52,10 @@ export function setUser(user: IUser) {
}; };
} }
export const LEVEL_SET_REVIEW = "LEVEL_SET_REVIEW";
export function setLevelReview(state: boolean) {
return {
type: LEVEL_SET_REVIEW,
state,
};
};
export const LEVEL_SET_LOOKEDAT = "LEVEL_SET_LOOKEDAT"; export const LEVEL_SET_LOOKEDAT = "LEVEL_SET_LOOKEDAT";
export function setLevelLookedAt(ids: number[]) { export function setLevelLookedAt(ids: number[]) {
return { return {
type: LEVEL_SET_REVIEW, type: LEVEL_SET_LOOKEDAT,
lookedAt: ids, lookedAt: ids,
}; };
}; };

View File

@ -10,7 +10,7 @@ import LoginPage from "../containers/LoginPage";
import LevelListPage from "../containers/LevelList"; import LevelListPage from "../containers/LevelList";
import LevelPage from "../containers/LevelPage"; import LevelPage from "../containers/LevelPage";
import ReviewPage from "../containers/Review"; import ReviewPage from "../containers/Review";
import SummaryPage from "../pages/summary"; import SummaryPage from "../containers/SummaryPage";
import WelcomePage from "../pages/intro"; import WelcomePage from "../pages/intro";
import Drawer from "../containers/Drawer"; import Drawer from "../containers/Drawer";
@ -309,8 +309,7 @@ export default class Application extends React.Component<IProps> {
isAuth={this.isAuthenticated} isAuth={this.isAuthenticated}
path="/review/summary" path="/review/summary"
component={() => { component={() => {
return <SummaryPage return <SummaryPage />
reviewMeta={this.getLastReview} />
}} /> }} />
</div> </div>
</div > </div >

View File

@ -1,7 +1,7 @@
import { connect } from "react-redux"; import { connect } from "react-redux";
import { import {
setDrawerButton, setLevelReview, setLevelLookedAt, setDrawerButton, setLevelLookedAt,
setLevelCurrentVocab, setLevelVocab, setLevelLoading setLevelCurrentVocab, setLevelVocab, setLevelLoading
} from "../actions"; } from "../actions";
@ -10,12 +10,11 @@ import { IVocab } from "../models/vocab";
import LevelPage from "../pages/level"; import LevelPage from "../pages/level";
const mapStateToProps = state => { const mapStateToProps = state => {
const { currentVocab, lookedAt, toReview, vocab, loading } = state.level; const { currentVocab, lookedAt, vocab, loading } = state.level;
return { return {
currentVocab, currentVocab,
lookedAt, lookedAt,
toReview,
vocab, vocab,
loading, loading,
}; };
@ -24,7 +23,6 @@ const mapStateToProps = state => {
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
drawerButtonState: (state: boolean) => dispatch(setDrawerButton(state)), drawerButtonState: (state: boolean) => dispatch(setDrawerButton(state)),
setReview: (state: boolean) => dispatch(setLevelReview(state)),
setLookedAt: (ids: number[]) => dispatch(setLevelLookedAt(ids)), setLookedAt: (ids: number[]) => dispatch(setLevelLookedAt(ids)),
setCurrentVocab: (vocab: IVocab) => dispatch(setLevelCurrentVocab(vocab)), setCurrentVocab: (vocab: IVocab) => dispatch(setLevelCurrentVocab(vocab)),
setVocab: (vocab: IVocab[]) => dispatch(setLevelVocab(vocab)), setVocab: (vocab: IVocab[]) => dispatch(setLevelVocab(vocab)),

View File

@ -0,0 +1,21 @@
import { connect } from "react-redux";
import { setDrawerButton } from "../actions";
import SummaryPage from "../pages/summary";
const mapStateToProps = state => {
return {
reviewMeta: state.lastReview,
};
};
const mapDispatchToProps = dispatch => {
return {
setDrawerButton: (state: boolean) => dispatch(setDrawerButton(state)),
};
};
const SummaryPageContainer = connect(mapStateToProps,
mapDispatchToProps)(SummaryPage);
export default SummaryPageContainer;

View File

@ -10,7 +10,7 @@ import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress";
import { Redirect } from "react-router-dom"; import { withRouter } from "react-router-dom";
import { IVocab } from "../models/vocab"; import { IVocab } from "../models/vocab";
@ -18,183 +18,170 @@ interface IProps {
id: string; id: string;
levelVocab: (id: string) => Promise<IVocab[]>; levelVocab: (id: string) => Promise<IVocab[]>;
history: any;
loading: boolean; loading: boolean;
setLoading: (state: boolean) => void; setLoading: (state: boolean) => void;
vocab: IVocab[]; vocab: IVocab[];
setVocab: (vocab: IVocab[]) => void; setVocab: (vocab: IVocab[]) => void;
setLookedAt: (ids: number[]) => void; setLookedAt: (ids: number[]) => void;
setCurrentVocab: (vocab: IVocab) => void; setCurrentVocab: (vocab: IVocab) => void;
setReview: (state: boolean) => void;
drawerButtonState: (state: boolean) => void; drawerButtonState: (state: boolean) => void;
currentVocab: IVocab; currentVocab: IVocab;
lookedAt: number[]; lookedAt: number[];
toReview: boolean;
}; };
export default class LevelPage extends React.Component<IProps> { const LevelPageWithRouter = withRouter(
private uid = 0; class LevelPage extends React.Component<IProps> {
// To prevent React from redrawing the vocabulary list and prematurely private uid = 0;
// cancelling the animation // To prevent React from redrawing the vocabulary list and prematurely
private uids: { [key: string]: string } = {}; // cancelling the animation
private uids: { [key: string]: string } = {};
componentDidMount() { componentDidMount() {
// Hide the drawer // Hide the drawer
this.props.drawerButtonState(false); this.props.drawerButtonState(false);
// Fetch the vocabulary // Fetch the vocabulary
this.props.setLoading(true); this.props.setLoading(true);
// TODO: Error handling // TODO: Error handling
this.props.levelVocab(this.props.id).then(vocab => { this.props.levelVocab(this.props.id).then(vocab => {
this.props.setVocab(vocab); this.props.setVocab(vocab);
this.props.setCurrentVocab(vocab[0]); this.props.setCurrentVocab(vocab[0]);
this.props.setLoading(false); this.props.setLoading(false);
}); });
}
genUID = (vocab: IVocab): string => {
const { grundform } = vocab.latin;
if (grundform in this.uids) {
return this.uids[grundform];
} else {
this.uids[grundform] = "LEVELPAGE" + this.uid++;
return this.uids[grundform];
} }
}
renderVocabListItem = (vocab: IVocab): any => { genUID = (vocab: IVocab): string => {
// Check if the vocab was already looked at const { grundform } = vocab.latin;
const lookedAt = this.props.lookedAt.find((el) => el === vocab.id) || vocab.id === 0; if (grundform in this.uids) {
return this.uids[grundform];
return <ListItem button key={this.genUID(vocab)} onClick={() => { } else {
// Prevent the user from using too much memory by always clicking on the elements this.uids[grundform] = "LEVELPAGE" + this.uid++;
// Show the clicked at vocab word return this.uids[grundform];
}
this.props.setCurrentVocab(vocab);
this.props.setLookedAt(lookedAt ? (
this.props.lookedAt
) : this.props.lookedAt.concat(vocab.id));
}}>
<ListItemText>
{`${vocab.latin.grundform} ${lookedAt ? "✔" : ""}`}
</ListItemText>
</ListItem>;
}
toReview = () => {
const { vocab, lookedAt } = this.props;
// Only go to the review if all vocabulary item have been looked at
if (vocab.length === lookedAt.length) {
this.props.setReview(true);
} }
}
render() { renderVocabListItem = (vocab: IVocab): any => {
if (this.props.loading) { // Check if the vocab was already looked at
return <div> const lookedAt = this.props.lookedAt.find((el) => el === vocab.id) || vocab.id === 0;
{/*
* This would be the case when the user presses the "to return <ListItem button key={this.genUID(vocab)} onClick={() => {
* review" button. That is because we need the state of loading // Prevent the user from using too much memory by always clicking on the elements
* to be true, when this page gets called // Show the clicked at vocab word
* TODO:?
*/} this.props.setCurrentVocab(vocab);
{ this.props.setLookedAt(lookedAt ? (
this.props.toReview ? ( this.props.lookedAt
<Redirect to={`/review/level/${this.props.id}`} /> ) : this.props.lookedAt.concat(vocab.id));
) : undefined }}>
} <ListItemText>
<Grid {`${vocab.latin.grundform} ${lookedAt ? "✔" : ""}`}
container </ListItemText>
spacing={0} </ListItem>;
direction="column" }
alignItems="center"
justify="center" toReview = () => {
style={{ minHeight: '100vh' }}> const { vocab, lookedAt, id } = this.props;
<Grid item xs={12}> // Only go to the review if all vocabulary item have been looked at
<Paper className="paper"> if (vocab.length === lookedAt.length) {
<Grid container direction="column" spacing={8}> this.props.setLoading(true);
<CircularProgress /> this.props.history.push(`/review/level/${id}`);
</Grid> }
</Paper> }
render() {
if (this.props.loading) {
return <div>
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justify="center"
style={{ minHeight: '100vh' }}>
<Grid item xs={12}>
<Paper className="paper">
<Grid container direction="column" spacing={8}>
<CircularProgress />
</Grid>
</Paper>
</Grid>
</Grid> </Grid>
</Grid>
</div>; </div>;
} }
const { currentVocab } = this.props; const { currentVocab } = this.props;
return <div> return <div>
<Grid container direction="row"> <Grid container direction="row">
<Grid item xs={3}> <Grid item xs={3}>
<List> <List>
{this.props.vocab {this.props.vocab
.map(this.renderVocabListItem)} .map(this.renderVocabListItem)}
{/* TODO*/} <ListItem button onClick={this.toReview}>
<ListItem button onClick={this.toReview}> <ListItemText>
<ListItemText> Zur Übung
Zur Übung
</ListItemText> </ListItemText>
</ListItem> </ListItem>
</List> </List>
</Grid> </Grid>
{ <Grid item lg={7} xs={9}>
this.props.toReview ? ( <Grid container direction="column">
<Redirect to={`/review/level/${this.props.id}`} /> <Grid item style={{ margin: 12 }}>
) : undefined <Card>
} <CardContent>
<Grid item lg={7} xs={9}> <Typography gutterBottom variant="headline" component="h2">
<Grid container direction="column"> {currentVocab.latin.grundform}
<Grid item style={{ margin: 12 }}> </Typography>
<Card> <Typography gutterBottom variant="headline" component="h3">
<CardContent> {currentVocab.german.join(", ")}
<Typography gutterBottom variant="headline" component="h2"> </Typography>
{currentVocab.latin.grundform} {
</Typography> currentVocab.hint ? (
<Typography gutterBottom variant="headline" component="h3"> <div style={{
{currentVocab.german.join(", ")} border: "dashed",
</Typography> borderColor: "red",
{ padding: 12,
currentVocab.hint ? ( }}>
<div style={{ <Typography variant="subheading" component="p">
border: "dashed", <b>Tipp:</b>
borderColor: "red", </Typography>
padding: 12, <Typography variant="body2">
}}> {currentVocab.hint}
<Typography variant="subheading" component="p"> </Typography>
<b>Tipp:</b> </div>
</Typography> ) : undefined
<Typography variant="body2"> }
{currentVocab.hint} {
</Typography> currentVocab.mnemonic ? (
</div> <div style={{
) : undefined border: "dashed",
} borderColor: "#f1c40f",
{ marginTop: 12,
currentVocab.mnemonic ? ( padding: 12,
<div style={{ }}>
border: "dashed", <Typography variant="subheading" component="p">
borderColor: "#f1c40f", <b>Eselsbrücke:</b>
marginTop: 12, </Typography>
padding: 12, <Typography variant="body2">
}}> {currentVocab.mnemonic}
<Typography variant="subheading" component="p"> </Typography>
<b>Eselsbrücke:</b> </div>
</Typography> ) : undefined
<Typography variant="body2"> }
{currentVocab.mnemonic} </CardContent>
</Typography> {/*TODO: Maybe "next" and "prev" buttons?*/}
</div> </Card>
) : undefined </Grid>
}
</CardContent>
{/*TODO: Maybe "next" and "prev" buttons?*/}
</Card>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </div>;
</div>; }
} }
}; );
export default LevelPageWithRouter;

View File

@ -6,55 +6,51 @@ import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import SummaryTable from "../components/SummaryTable"; import SummaryTable from "../components/SummaryTable";
import { Redirect } from "react-router-dom"; import { withRouter } from "react-router-dom";
import { IReviewMetadata } from "../models/review"; import { IReviewMetadata } from "../models/review";
interface IProps { interface IProps {
reviewMeta: () => IReviewMetadata; history: any;
reviewMeta: IReviewMetadata;
setDrawerButton: (state: boolean) => void;
} }
interface IState { // TODO: This stays at the default value
toDashboard: boolean; const SummaryPageWithRouter = withRouter(
} class SummaryPage extends React.Component<IProps> {
toDashboard = () => {
// Show the drawer button
this.props.setDrawerButton(true);
export default class SummaryPage extends React.Component<IProps, IState> { // Go to the dashboard
constructor(props: any) { this.props.history.push("/dashboard");
super(props); }
this.state = { render() {
toDashboard: false, return <div>
}; <Grid
} container
spacing={0}
render() { direction="column"
return <div> alignItems="center"
{ justify="center"
this.state.toDashboard ? ( style={{ minHeight: '100vh' }}>
<Redirect to="/dashboard" /> <Grid item xs={12}>
) : undefined <Paper className="paper">
} <Typography variant="title">Zusammenfassung</Typography>
<Grid <Grid container direction="column">
container <SummaryTable reviewMeta={() => this.props.reviewMeta} />
spacing={0} <Button onClick={this.toDashboard}>
direction="column" Zum Dashboard
alignItems="center"
justify="center"
style={{ minHeight: '100vh' }}>
<Grid item xs={12}>
<Paper className="paper">
<Typography variant="title">Zusammenfassung</Typography>
<Grid container direction="column">
<SummaryTable reviewMeta={this.props.reviewMeta} />
<Button onClick={() => this.setState({
toDashboard: true,
})}>
Zum Dashboard
</Button> </Button>
</Grid> </Grid>
</Paper> </Paper>
</Grid>
</Grid> </Grid>
</Grid> </div>;
</div>; }
} }
} );
export default SummaryPageWithRouter;

View File

@ -26,7 +26,6 @@ interface IState {
level: { level: {
currentVocab: IVocab; currentVocab: IVocab;
lookedAt: number[]; lookedAt: number[];
toReview: boolean;
vocab: IVocab[]; vocab: IVocab[];
loading: boolean; loading: boolean;
}; };
@ -74,7 +73,6 @@ const initialState: IState = {
level: { level: {
currentVocab: {} as IVocab, currentVocab: {} as IVocab,
lookedAt: [0], lookedAt: [0],
toReview: false,
vocab: [], vocab: [],
loading: true, loading: true,
}, },
@ -137,15 +135,6 @@ export function LateinicusApp(state: IState = initialState, action: any) {
return Object.assign({}, state, { return Object.assign({}, state, {
user: action.user, user: action.user,
}); });
case Actions.LEVEL_SET_REVIEW:
return Object.assign({}, state, {
level: Object.assign({}, state.level, {
toReview: action.state,
// Make sure that we are in a "loading mode", when the page gets
// called the next time
loading: true,
}),
});
case Actions.LEVEL_SET_LOOKEDAT: case Actions.LEVEL_SET_LOOKEDAT:
return Object.assign({}, state, { return Object.assign({}, state, {
level: Object.assign({}, state.level, { level: Object.assign({}, state.level, {