diff --git a/package.json b/package.json
index 84aeb3d..d274db0 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
+ "@hookform/resolvers": "^3.3.1",
"@mui/icons-material": "^5.14.9",
"@mui/material": "^5.14.10",
"dayjs": "^1.11.10",
diff --git a/src/app/api/hello/route.ts b/src/app/api/hello/route.ts
deleted file mode 100644
index 7ac9b84..0000000
--- a/src/app/api/hello/route.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { NextResponse } from 'next/server';
-
-export async function GET() {
- return NextResponse.json({ message: 'Test getApiResponse success!' });
-}
diff --git a/src/app/api/test/route.ts b/src/app/api/test/route.ts
new file mode 100644
index 0000000..53ab123
--- /dev/null
+++ b/src/app/api/test/route.ts
@@ -0,0 +1,20 @@
+import { NextResponse } from 'next/server';
+
+export const GET = async (req: Request) => {
+ const { searchParams } = new URL(req.url);
+ const reqData = Object.fromEntries(searchParams);
+ return NextResponse.json({
+ message: 'Test getApiResponse GET success!',
+ method: 'GET',
+ reqData,
+ });
+};
+
+export const POST = async (req: Request) => {
+ const reqData = await req.json();
+ return NextResponse.json({
+ message: 'Test postApiResponse POST success!',
+ method: 'POST',
+ reqData,
+ });
+};
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 1b07f90..f0157b6 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,7 +1,9 @@
+import { Container } from '@mui/material';
+import GlobalStyles from '@mui/material/GlobalStyles';
import { Metadata } from 'next';
import * as React from 'react';
-import { SITE_CONFIG } from '@/constant/config';
+import { GLOBAL_STYLES, SITE_CONFIG } from '@/constant';
// !STARTERCONF Change these default meta
// !STARTERCONF Look at @/constant/config to change them
@@ -50,8 +52,11 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
-
{children}
+
+
+
+ {children}
+
);
}
diff --git a/src/component/Homepage.tsx b/src/component/Homepage.tsx
index 812e3d6..772fe20 100644
--- a/src/component/Homepage.tsx
+++ b/src/component/Homepage.tsx
@@ -3,6 +3,7 @@ import { Box, Typography } from '@mui/material';
import Link from 'next/link';
import PageFooter from '@/component/shared/PageFooter';
+import ReactHookForm from '@/component/shared/ReactHookForm';
import { SITE_CONFIG } from '@/constant';
export default function Homepage({ reactVersion = 'unknown' }) {
@@ -11,10 +12,19 @@ export default function Homepage({ reactVersion = 'unknown' }) {
-
+
{SITE_CONFIG.title}
-
+
{SITE_CONFIG.description}
@@ -42,6 +52,20 @@ export default function Homepage({ reactVersion = 'unknown' }) {
Click here to deploy a demo site to your Vercel in 1 minute
+
+
+ Test NextJs API method GET with parameters
+
+
+
+
+ Test NextJs API method POST with parameters
+
+
+
Test 404 page not found
diff --git a/src/component/shared/PageFooter.tsx b/src/component/shared/PageFooter.tsx
index ec2560d..ab5c9a0 100644
--- a/src/component/shared/PageFooter.tsx
+++ b/src/component/shared/PageFooter.tsx
@@ -1,15 +1,20 @@
import { Box } from '@mui/material';
import * as React from 'react';
+import ServerDateTime from '@/component/shared/ServerDateTime';
+
const PageFooter = () => {
return (
- PageFooter.tsx © {new Date().getFullYear()} Boilerplate live example:
+ PageFooter.tsx © Boilerplate live example:
HiHB
+
+
+
);
};
diff --git a/src/component/shared/ReactHookForm.tsx b/src/component/shared/ReactHookForm.tsx
new file mode 100644
index 0000000..8eaa2ad
--- /dev/null
+++ b/src/component/shared/ReactHookForm.tsx
@@ -0,0 +1,90 @@
+'use client';
+
+import { zodResolver } from '@hookform/resolvers/zod';
+import { Box, Button, FormHelperText } from '@mui/material';
+import React from 'react';
+import { Controller, SubmitHandler, useForm } from 'react-hook-form';
+import { z } from 'zod';
+
+import { consoleLog } from '@/util/shared/console-log';
+import { getApiResponse } from '@/util/shared/get-api-response';
+
+const zodSchema = z.object({
+ name: z.string().min(5).nonempty({ message: 'Name is required' }),
+ email: z.string().min(10).email({ message: 'Invalid email address' }),
+});
+
+type FormValues = z.infer;
+
+const ReactHookForm: React.FC = () => {
+ const apiEndpoint = '/api/test';
+ const [apiResult, setApiResult] = React.useState();
+
+ const {
+ handleSubmit,
+ control,
+ formState: { errors },
+ } = useForm({
+ resolver: zodResolver(zodSchema),
+ });
+
+ const onSubmit: SubmitHandler = async (data) => {
+ try {
+ const result = await getApiResponse<{
+ reqData: FormValues;
+ }>({
+ apiEndpoint,
+ method: 'POST',
+ requestData: JSON.stringify(data),
+ });
+ setApiResult(result?.reqData);
+ consoleLog('getApiResponse result', result, errors);
+ } catch (error) {
+ consoleLog('handleSubmit ERROR', error);
+ }
+ };
+
+ return (
+
+ );
+};
+
+export default ReactHookForm;
diff --git a/src/component/shared/ServerDateTime.tsx b/src/component/shared/ServerDateTime.tsx
new file mode 100644
index 0000000..12a5ec6
--- /dev/null
+++ b/src/component/shared/ServerDateTime.tsx
@@ -0,0 +1,26 @@
+import dayjs from 'dayjs';
+import timezone from 'dayjs/plugin/timezone';
+import utc from 'dayjs/plugin/utc';
+
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+const ServerDateTime = ({
+ cityTimezone,
+ timeFormat = 'dddd, MMMM D, YYYY h:mm:ss A',
+ color,
+ date,
+}: {
+ cityTimezone: string;
+ timeFormat?: string;
+ color?: string;
+ date?: string;
+}) => {
+ return (
+
+ {dayjs(date).tz(cityTimezone).format(timeFormat)}
+
+ );
+};
+
+export default ServerDateTime;
diff --git a/src/constant/config.ts b/src/constant/config.ts
index 415887d..3efbf66 100644
--- a/src/constant/config.ts
+++ b/src/constant/config.ts
@@ -1,3 +1,5 @@
+import { blue, grey } from '@mui/material/colors';
+
export const SITE_CONFIG = {
title: 'NextJs 13.x + MUI 5.x + TypeScript Starter',
description:
@@ -10,3 +12,18 @@ export const HIDE_DEBUG_ARY = [
// 'getApiResponse',
'getMongoDbApiData',
];
+
+export const GLOBAL_STYLES = {
+ body: { margin: 4 },
+ '.page-title': { color: 'darkblue' },
+ '.page-subtitle': { color: grey[600] },
+ a: {
+ textDecoration: 'underline',
+ textDecorationColor: blue[800],
+ color: blue['700'],
+ fontSize: '1rem',
+ fontWeight: 400,
+ lineHeight: '1.8',
+ letterSpacing: '0.00938em',
+ },
+};
diff --git a/yarn.lock b/yarn.lock
index a4eec41..7eadaef 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1373,6 +1373,11 @@
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d"
integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA==
+"@hookform/resolvers@^3.3.1":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.3.1.tgz#b7cbfe767434f52cba6b99b0a9a0b73eb8895188"
+ integrity sha512-K7KCKRKjymxIB90nHDQ7b9nli474ru99ZbqxiqDAWYsYhOsU3/4qLxW91y+1n04ic13ajjZ66L3aXbNef8PELQ==
+
"@humanwhocodes/config-array@^0.11.11":
version "0.11.11"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"