Timeline component

master
Tudor Stanciu 2023-03-26 22:36:26 +03:00
parent 853cc9c9ad
commit 99b4929b2a
9 changed files with 180 additions and 16 deletions

View File

@ -64,7 +64,8 @@
"About": { "About": {
"Navigation": { "Navigation": {
"System": "System", "System": "System",
"ReleaseNotes": "Release notes" "ReleaseNotes": "Release notes",
"Timeline": "Timeline"
}, },
"ReleaseNotes": { "ReleaseNotes": {
"Version": "Version", "Version": "Version",

View File

@ -55,7 +55,8 @@
"About": { "About": {
"Navigation": { "Navigation": {
"System": "Sistem", "System": "Sistem",
"ReleaseNotes": "Note de lansare" "ReleaseNotes": "Note de lansare",
"Timeline": "Cronologie"
}, },
"ReleaseNotes": { "ReleaseNotes": {
"Version": "Versiune", "Version": "Versiune",

View File

@ -2,6 +2,7 @@ import React, { useState, useMemo } from "react";
import PageTitle from "../../components/common/PageTitle"; import PageTitle from "../../components/common/PageTitle";
import BubbleChartIcon from "@material-ui/icons/BubbleChart"; import BubbleChartIcon from "@material-ui/icons/BubbleChart";
import NotesIcon from "@material-ui/icons/Notes"; import NotesIcon from "@material-ui/icons/Notes";
import TimelineIcon from "@material-ui/icons/Timeline";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import AboutSystemContainer from "./system/AboutSystemContainer"; import AboutSystemContainer from "./system/AboutSystemContainer";
import ReleaseNotesContainer from "./releaseNotes/ReleaseNotesContainer"; import ReleaseNotesContainer from "./releaseNotes/ReleaseNotesContainer";
@ -9,7 +10,8 @@ import NavigationButtons from "../../components/common/NavigationButtons";
const NavigationTabs = { const NavigationTabs = {
SYSTEM: "About.Navigation.System", SYSTEM: "About.Navigation.System",
RELEASE_NOTES: "About.Navigation.ReleaseNotes" RELEASE_NOTES: "About.Navigation.ReleaseNotes",
TIMELINE: "About.Navigation.Timeline"
}; };
const tabs = [ const tabs = [
@ -20,6 +22,10 @@ const tabs = [
{ {
code: NavigationTabs.RELEASE_NOTES, code: NavigationTabs.RELEASE_NOTES,
icon: NotesIcon icon: NotesIcon
},
{
code: NavigationTabs.TIMELINE,
icon: TimelineIcon
} }
]; ];
@ -42,6 +48,9 @@ const AboutContainer = () => {
/> />
{tab === NavigationTabs.SYSTEM && <AboutSystemContainer />} {tab === NavigationTabs.SYSTEM && <AboutSystemContainer />}
{tab === NavigationTabs.RELEASE_NOTES && <ReleaseNotesContainer />} {tab === NavigationTabs.RELEASE_NOTES && <ReleaseNotesContainer />}
{tab === NavigationTabs.TIMELINE && (
<ReleaseNotesContainer view="timeline" />
)}
</> </>
); );
}; };

View File

@ -1,8 +1,13 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import useApi from "../../../api"; import useApi from "../../../api";
import ReleaseNotesList from "./ReleaseNotesList"; import ReleaseNotesList from "./ReleaseNotesList";
import TimelineComponent from "../timeline/TimelineComponent";
const ReleaseNotesContainer = () => { const sort = releases =>
releases.sort((a, b) => new Date(b.date) - new Date(a.date));
const ReleaseNotesContainer = ({ view }) => {
const [state, setState] = useState({ data: [], loaded: false }); const [state, setState] = useState({ data: [], loaded: false });
const api = useApi(); const api = useApi();
@ -16,7 +21,20 @@ const ReleaseNotesContainer = () => {
}); });
}, [api, state.loaded]); }, [api, state.loaded]);
return <>{state.loaded && <ReleaseNotesList releaseNotes={state.data} />}</>; return (
<>
{state.loaded &&
(view === "timeline" ? (
<TimelineComponent releases={sort(state.data)} />
) : (
<ReleaseNotesList releases={sort(state.data)} />
))}
</>
);
};
ReleaseNotesContainer.propTypes = {
view: PropTypes.string
}; };
export default ReleaseNotesContainer; export default ReleaseNotesContainer;

View File

@ -9,7 +9,7 @@ import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import ReleaseNoteSummary from "./ReleaseNoteSummary"; import ReleaseNoteSummary from "./ReleaseNoteSummary";
import ReleaseNote from "./ReleaseNote"; import ReleaseNote from "./ReleaseNote";
const ReleaseNotesList = ({ releaseNotes }) => { const ReleaseNotesList = ({ releases }) => {
const [flags, setFlags] = useState({}); const [flags, setFlags] = useState({});
const handleToggle = key => (_, expanded) => { const handleToggle = key => (_, expanded) => {
@ -25,22 +25,30 @@ const ReleaseNotesList = ({ releaseNotes }) => {
return collapsed; return collapsed;
}; };
console.log(
"sortedReleases",
JSON.stringify(releases.map(z => ({ version: z.version, date: z.date })))
);
return ( return (
<> <>
{releaseNotes.map(note => { {releases.map(release => {
return ( return (
<Accordion key={note.version} onChange={handleToggle(note.version)}> <Accordion
key={release.version}
onChange={handleToggle(release.version)}
>
<AccordionSummary <AccordionSummary
expandIcon={<ExpandMoreIcon />} expandIcon={<ExpandMoreIcon />}
id={`panel-${note.version}-header`} id={`panel-${release.version}-header`}
> >
<ReleaseNoteSummary <ReleaseNoteSummary
releaseNote={note} releaseNote={release}
collapsed={isCollapsed(note.version)} collapsed={isCollapsed(release.version)}
/> />
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<ReleaseNote releaseNote={note} /> <ReleaseNote releaseNote={release} />
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
); );
@ -50,7 +58,7 @@ const ReleaseNotesList = ({ releaseNotes }) => {
}; };
ReleaseNotesList.propTypes = { ReleaseNotesList.propTypes = {
releaseNotes: PropTypes.array.isRequired releases: PropTypes.array.isRequired
}; };
export default ReleaseNotesList; export default ReleaseNotesList;

View File

@ -0,0 +1,117 @@
import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/core/styles";
import Timeline from "@material-ui/lab/Timeline";
import TimelineItem from "@material-ui/lab/TimelineItem";
import TimelineSeparator from "@material-ui/lab/TimelineSeparator";
import TimelineConnector from "@material-ui/lab/TimelineConnector";
import TimelineContent from "@material-ui/lab/TimelineContent";
import TimelineOppositeContent from "@material-ui/lab/TimelineOppositeContent";
import TimelineDot from "@material-ui/lab/TimelineDot";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
import { useTranslation } from "react-i18next";
import { getRandomElement } from "../../../utils";
import {
Announcement,
AmpStories,
Apps,
BugReport,
DeviceHub,
Equalizer,
FilterTiltShift,
Grain,
Layers,
LocalOffer,
Memory,
NetworkCheck,
OfflineBolt,
Star,
Whatshot,
Widgets
} from "@material-ui/icons";
const timelineIcons = [
Announcement,
AmpStories,
Apps,
BugReport,
DeviceHub,
Equalizer,
FilterTiltShift,
Grain,
Layers,
LocalOffer,
Memory,
NetworkCheck,
OfflineBolt,
Star,
Whatshot,
Widgets
];
const timelineDotVariants = [
{ color: "primary", variant: "outlined" },
{ color: "secondary", variant: "outlined" }
];
const useStyles = makeStyles(() => ({
paper: {
padding: "6px 16px"
}
}));
const TimelineComponent = ({ releases }) => {
const classes = useStyles();
const { t } = useTranslation();
const _releases = releases.map((release, index) => {
const isLast = index === releases.length - 1;
const icon = getRandomElement(timelineIcons);
const dot = getRandomElement(timelineDotVariants);
return { ...release, isLast, icon, dot };
});
return (
<Timeline align="alternate">
{_releases.map(release => (
<TimelineItem key={release.version}>
<TimelineOppositeContent>
<Typography variant="body2" color="textSecondary">
{t("DATE_FORMAT", {
date: { value: release.date, format: "DD-MM-YYYY HH:mm" }
})}
</Typography>
</TimelineOppositeContent>
<TimelineSeparator>
<TimelineDot
color={release.dot.color}
variant={release.dot.variant}
>
<release.icon />
</TimelineDot>
{!release.isLast && <TimelineConnector />}
</TimelineSeparator>
<TimelineContent>
<Paper elevation={3} className={classes.paper}>
<Typography variant="h6" component="h1">
{release.notes[0]}
</Typography>
{release.notes.slice(1).map((note, index) => (
<Typography key={index} variant="body2">
{note}
</Typography>
))}
</Paper>
</TimelineContent>
</TimelineItem>
))}
</Timeline>
);
};
TimelineComponent.propTypes = {
releases: PropTypes.array.isRequired
};
export default TimelineComponent;

View File

@ -1,5 +1,5 @@
const primary = "#00695C"; const primary = "#00695C";
const secondary = "#FF5C93"; const secondary = "#F9A825";
const warning = "#ff9800"; const warning = "#ff9800";
const success = "#4caf50"; const success = "#4caf50";
const info = "#2196f3"; const info = "#2196f3";
@ -10,8 +10,8 @@ const defaultTheme = {
main: primary main: primary
}, },
secondary: { secondary: {
main: secondary, main: secondary
contrastText: "#ffcc00" // contrastText: "#ffcc00"
}, },
warning: { warning: {
main: warning main: warning

3
src/utils/index.js Normal file
View File

@ -0,0 +1,3 @@
import { getRandomElement } from "./random";
export { getRandomElement };

7
src/utils/random.js Normal file
View File

@ -0,0 +1,7 @@
const getRandomElement = array => {
const randomIndex = Math.floor(Math.random() * array.length);
const element = array[randomIndex];
return element;
};
export { getRandomElement };