= (props) => {
10 | return (
11 |
12 |
13 |
14 |
15 |
{props.pageTitle}
16 |
17 | {props.children}
18 |
19 | );
20 | };
21 |
22 | export default WithNavigationLayout;
23 |
--------------------------------------------------------------------------------
/src/configs/theme.ts:
--------------------------------------------------------------------------------
1 | import { createMuiTheme, Theme } from "@material-ui/core/styles";
2 |
3 | const theme: Theme = createMuiTheme({
4 | palette: {
5 | primary: {
6 | light: "#484848",
7 | main: "#212121",
8 | dark: "#000000",
9 | contrastText: "#ffffff",
10 | },
11 | secondary: {
12 | light: "#99d066",
13 | main: "#689f38",
14 | dark: "#387002",
15 | contrastText: "#000000",
16 | },
17 | },
18 | });
19 |
20 | export default theme;
21 |
--------------------------------------------------------------------------------
/src/models/Task/Factory.ts:
--------------------------------------------------------------------------------
1 | import { nanoid } from "nanoid";
2 | import Task from "./Task";
3 | import { Id } from "./Id";
4 | import { Status } from "./Status";
5 | import { Title } from "./Title";
6 |
7 | export interface Input {
8 | id?: string;
9 | title: string;
10 | status?: number;
11 | archived?: boolean;
12 | createdAt?: number;
13 | }
14 |
15 | export class Factory {
16 | public static create(props: Input): Task {
17 | return new Task({
18 | id: new Id(props.id ? props.id : nanoid()),
19 | title: new Title(props.title),
20 | status: new Status(
21 | props.status !== undefined ? props.status : Status.READY
22 | ),
23 | archived: props.archived !== undefined ? props.archived : false,
24 | createdAt: props.createdAt ? new Date(props.createdAt) : new Date(),
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/models/Task/Id.ts:
--------------------------------------------------------------------------------
1 | import { nanoid } from "nanoid";
2 |
3 | export class Id {
4 | readonly val: string;
5 |
6 | constructor(id?: string) {
7 | this.val = id || nanoid();
8 | }
9 |
10 | public getValue(): string {
11 | return this.val;
12 | }
13 | }
14 |
15 | export default {
16 | Id,
17 | };
18 |
--------------------------------------------------------------------------------
/src/models/Task/Mock.ts:
--------------------------------------------------------------------------------
1 | import { Factory } from "./Factory";
2 |
3 | const getTaskList = () => {
4 | return [
5 | Factory.create({
6 | id: "abcdefghijkLMNOPQRST1",
7 | title: "task 1",
8 | status: 0,
9 | }),
10 | Factory.create({
11 | id: "abcdefghijkLMNOPQRST2",
12 | title: "task 2",
13 | status: 1,
14 | }),
15 | Factory.create({
16 | id: "abcdefghijkLMNOPQRST3",
17 | title: "task 3",
18 | status: 0,
19 | }),
20 | Factory.create({
21 | id: "abcdefghijkLMNOPQRST4",
22 | title: "task 4",
23 | status: 0,
24 | archived: true,
25 | }),
26 | Factory.create({
27 | id: "abcdefghijkLMNOPQRST5",
28 | title: "task 5",
29 | status: 1,
30 | archived: true,
31 | }),
32 | ];
33 | };
34 |
35 | const getSerializedTaskList = () => {
36 | const tasks = getTaskList();
37 | return tasks.map((task) => task.serialize());
38 | };
39 |
40 | export default {
41 | getTaskList,
42 | getSerializedTaskList,
43 | };
44 |
--------------------------------------------------------------------------------
/src/models/Task/Status.ts:
--------------------------------------------------------------------------------
1 | export class Status {
2 | readonly val: number;
3 |
4 | static READY = 0;
5 |
6 | static COMPLETED = 1;
7 |
8 | constructor(status?: number) {
9 | this.val = status || Status.READY;
10 | }
11 |
12 | public isCompleted(): boolean {
13 | return this.val === Status.COMPLETED;
14 | }
15 |
16 | public getValue(): number {
17 | return this.val;
18 | }
19 | }
20 |
21 | export default {
22 | Status,
23 | };
24 |
--------------------------------------------------------------------------------
/src/models/Task/Task.ts:
--------------------------------------------------------------------------------
1 | import { Id } from "./Id";
2 | import { Status } from "./Status";
3 | import { Title } from "./Title";
4 |
5 | export class Task {
6 | private id: Id;
7 |
8 | private title: Title;
9 |
10 | private status: Status;
11 |
12 | private archived: boolean;
13 |
14 | private createdAt: Date;
15 |
16 | constructor(props: {
17 | id: Id;
18 | title: Title;
19 | status: Status;
20 | archived: boolean;
21 | createdAt: Date;
22 | }) {
23 | this.id = props.id;
24 | this.title = props.title;
25 | this.status = props.status;
26 | this.archived = props.archived;
27 | this.createdAt = props.createdAt;
28 | }
29 |
30 | public getId(): string {
31 | return this.id.getValue();
32 | }
33 |
34 | public getTitle(): string {
35 | return this.title.getValue();
36 | }
37 |
38 | public isCompleted(): boolean {
39 | return this.status.isCompleted();
40 | }
41 |
42 | public isArchived(): boolean {
43 | return this.archived;
44 | }
45 |
46 | public complete(): void {
47 | this.status = new Status(Status.COMPLETED);
48 | }
49 |
50 | public incomplete(): void {
51 | this.status = new Status(Status.READY);
52 | }
53 |
54 | public archive(): void {
55 | this.archived = true;
56 | }
57 |
58 | public unarchive(): void {
59 | this.archived = false;
60 | }
61 |
62 | public changeTitle(title: string): void {
63 | this.title = new Title(title);
64 | }
65 |
66 | public getCreatedTimestamp(): number {
67 | return this.createdAt.getTime();
68 | }
69 |
70 | public serialize() {
71 | return {
72 | id: this.getId(),
73 | title: this.getTitle(),
74 | status: this.status.getValue(),
75 | archived: this.archived,
76 | createdAt: this.createdAt.getTime(),
77 | };
78 | }
79 | }
80 |
81 | export default Task;
82 |
--------------------------------------------------------------------------------
/src/models/Task/Title.ts:
--------------------------------------------------------------------------------
1 | export class Title {
2 | readonly val: string;
3 |
4 | constructor(title: string) {
5 | if (title.length === 0) {
6 | throw new Error("Title is null or empty.");
7 | }
8 | this.val = title;
9 | }
10 |
11 | public getValue(): string {
12 | return this.val;
13 | }
14 | }
15 |
16 | export default {
17 | Title,
18 | };
19 |
--------------------------------------------------------------------------------
/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import { AppProps } from "next/app";
3 | import { MuiThemeProvider, StylesProvider } from "@material-ui/core";
4 | import CssBaseline from "@material-ui/core/CssBaseline";
5 | import { ThemeProvider } from "styled-components";
6 | import { Provider } from "react-redux";
7 | import theme from "../configs/theme";
8 | import store from "../states/store";
9 |
10 | const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {
11 | useEffect(() => {
12 | const jssStyles = document.querySelector("#jss-server-side");
13 | if (jssStyles && jssStyles.parentElement) {
14 | jssStyles.parentElement.removeChild(jssStyles);
15 | }
16 | }, []);
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | };
31 |
32 | export default MyApp;
33 |
--------------------------------------------------------------------------------
/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import Document, {
2 | DocumentContext,
3 | Head,
4 | Html,
5 | Main,
6 | NextScript,
7 | } from "next/document";
8 | import { ServerStyleSheet as StyledComponentSheets } from "styled-components";
9 | import { ServerStyleSheets as MaterialUiServerStyleSheets } from "@material-ui/core";
10 |
11 | export default class MyDocument extends Document {
12 | static async getInitialProps(ctx: DocumentContext) {
13 | const styledComponentSheets = new StyledComponentSheets();
14 | const materialUiServerStyleSheets = new MaterialUiServerStyleSheets();
15 | const originalRenderPage = ctx.renderPage;
16 |
17 | try {
18 | ctx.renderPage = () =>
19 | originalRenderPage({
20 | enhanceApp: (App) => (props) =>
21 | styledComponentSheets.collectStyles(
22 | materialUiServerStyleSheets.collect()
23 | ),
24 | });
25 |
26 | const initialProps = await Document.getInitialProps(ctx);
27 | return {
28 | ...initialProps,
29 | styles: (
30 | <>
31 | {initialProps.styles}
32 | {styledComponentSheets.getStyleElement()}
33 | {materialUiServerStyleSheets.getStyleElement()}
34 | >
35 | ),
36 | };
37 | } finally {
38 | styledComponentSheets.seal();
39 | }
40 | }
41 |
42 | render() {
43 | return (
44 |
45 |
46 |
47 |