init project portal web
This commit is contained in:
10
app/api/cookies/route.ts
Normal file
10
app/api/cookies/route.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function GET() {
|
||||
const cookieStore = cookies();
|
||||
const credential = JSON.parse(cookieStore.get("credential")?.value || "");
|
||||
|
||||
|
||||
return NextResponse.json({ credential });
|
||||
}
|
||||
55
app/api/login/route.ts
Normal file
55
app/api/login/route.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/auth/login`
|
||||
// GET REQUEST BODY
|
||||
const {username, password} = await request.json();
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: JSON.stringify({
|
||||
userName: username,
|
||||
password,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
if (response?.data ?? false) {
|
||||
const token: string = response.data.data.token;
|
||||
const expired = response.data.data.expired;
|
||||
const data = {
|
||||
username: response.data.data.username,
|
||||
token
|
||||
}
|
||||
cookies().set({
|
||||
name: 'credential',
|
||||
value: JSON.stringify(data),
|
||||
httpOnly: false,
|
||||
sameSite: 'strict',
|
||||
path: '/',
|
||||
maxAge: expired
|
||||
})
|
||||
}
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
18
app/api/logout/route.ts
Normal file
18
app/api/logout/route.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { cookies } from 'next/headers';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async () => {
|
||||
// Hapus cookie 'credential'
|
||||
cookies().delete({
|
||||
name: "credential",
|
||||
httpOnly: false,
|
||||
sameSite: 'strict',
|
||||
path: '/',
|
||||
maxAge: 0,
|
||||
})
|
||||
// Return a JSON response
|
||||
return NextResponse.json({
|
||||
message: 'Cookie deleted successfully.',
|
||||
status: 'success',
|
||||
}, { status: 200 });
|
||||
};
|
||||
36
app/api/priceplan-detail/usage-event/route.ts
Normal file
36
app/api/priceplan-detail/usage-event/route.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async () => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/usage_event/list`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
58
app/api/priceplan/create/route.ts
Normal file
58
app/api/priceplan/create/route.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const {
|
||||
offerType,
|
||||
offerName,
|
||||
pricePlanCode,
|
||||
remarks,
|
||||
sourceFrom,
|
||||
baseValidPeriod,
|
||||
serviceType,
|
||||
versionValidPeriod
|
||||
} = await request.json();
|
||||
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/createpriceplan`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
data: JSON.stringify({
|
||||
offerType,
|
||||
offerName,
|
||||
applyLevel: "S",
|
||||
pricePlanCode,
|
||||
remarks,
|
||||
sourceFrom,
|
||||
baseValidPeriod,
|
||||
versionValidPeriod,
|
||||
serviceType
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
36
app/api/priceplan/delete/route.ts
Normal file
36
app/api/priceplan/delete/route.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const {id} = await request.json();
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/delete/${id}`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
})
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
39
app/api/priceplan/menu/route.ts
Normal file
39
app/api/priceplan/menu/route.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async () => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/getmenuList`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
// console.log(token, 'cek token');
|
||||
|
||||
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
39
app/api/priceplan/route.ts
Normal file
39
app/api/priceplan/route.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const {page, size, type} = await request.json();
|
||||
let url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/list`
|
||||
if(type) url += `/${type}`
|
||||
url += `?page=${page}&size=${size}`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
36
app/api/priceplan/servetypes/route.ts
Normal file
36
app/api/priceplan/servetypes/route.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async () => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/getservtype`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
36
app/api/priceplan/types/route.ts
Normal file
36
app/api/priceplan/types/route.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async () => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/getalltype`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
55
app/api/rate-plan/create/route.ts
Normal file
55
app/api/rate-plan/create/route.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import axios from 'axios';
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
// INTERPOLATING API URL OF BACKEND
|
||||
const {
|
||||
offerVerId,
|
||||
offerType,
|
||||
reId,
|
||||
ratePlanName,
|
||||
ratePlanCode,
|
||||
remarks,
|
||||
ratePlanType,
|
||||
} = await request.json();
|
||||
|
||||
const url: string = `${process.env.NEXT_PUBLIC_API_URL}/priceplan/createpriceplan`
|
||||
const data = JSON.parse(cookies().get('credential')?.value ?? "")
|
||||
const token = `Bearer ${data.token}`
|
||||
|
||||
try {
|
||||
// MAKE AN API REQUEST
|
||||
/*
|
||||
* - WE USE AXIOS INSTEAD OF FETCH
|
||||
* - FETCH ALWAYS RETURNS "TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is already closed"
|
||||
* WHEN WE RUN "response.json()"
|
||||
*/
|
||||
const response = await axios(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token
|
||||
},
|
||||
data: JSON.stringify({
|
||||
offerVerId,
|
||||
offerType,
|
||||
reId,
|
||||
ratePlanName,
|
||||
ratePlanCode,
|
||||
remarks,
|
||||
ratePlanType,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json(response.data, { status: response.status });
|
||||
} catch (error: any) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return NextResponse.json(error.response?.data || { message: 'Unknown error' }, { status: error.response?.status || 500 });
|
||||
}
|
||||
return NextResponse.json({ message: 'An unexpected error occurred' }, { status: 500 });
|
||||
|
||||
}
|
||||
}
|
||||
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
98
app/globals.css
Normal file
98
app/globals.css
Normal file
@ -0,0 +1,98 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap');
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
--sidebar-background: 189 100% 31%;
|
||||
--sidebar-foreground: 0 0% 98%;
|
||||
--sidebar-primary: 240 5.9% 10%;
|
||||
--sidebar-primary-foreground: 0 0% 98%;
|
||||
--sidebar-accent: 240 4.8% 95.9%;
|
||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||
--sidebar-border: 220 13% 91%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--sidebar-background: 240 5.9% 10%;
|
||||
--sidebar-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-primary: 224.3 76.3% 48%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 240 3.7% 15.9%;
|
||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-border: 240 3.7% 15.9%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
font-family: "Outfit", sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
19
app/layout.tsx
Normal file
19
app/layout.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "OCS Portal Web",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body suppressHydrationWarning={true}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
15
app/main/layout.tsx
Normal file
15
app/main/layout.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import MainLayout from "@/components/layout/main-layout"
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const Layout = ({
|
||||
children
|
||||
}: Props) => {
|
||||
return (
|
||||
<MainLayout>{children}</MainLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default Layout
|
||||
16
app/main/price-plan/[id]/page.tsx
Normal file
16
app/main/price-plan/[id]/page.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import PricePlanDetail from "@/lib/price-plan-detail/view"
|
||||
|
||||
interface Props {
|
||||
params: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
const Page = ({params}: Props) => {
|
||||
const id = params.id
|
||||
return (
|
||||
<PricePlanDetail id={id}/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
9
app/main/price-plan/page.tsx
Normal file
9
app/main/price-plan/page.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import PricePlanList from "@/lib/price-plan/view"
|
||||
|
||||
const PricePlan = () => {
|
||||
return (
|
||||
<PricePlanList/>
|
||||
)
|
||||
}
|
||||
|
||||
export default PricePlan
|
||||
10
app/onboard/login/page.tsx
Normal file
10
app/onboard/login/page.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import Login from "@/lib/login/view"
|
||||
|
||||
|
||||
const LoginPage = () => {
|
||||
return (
|
||||
<Login/>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoginPage
|
||||
11
app/page.tsx
Normal file
11
app/page.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import AppBar from "@/components/module/app-bar"
|
||||
import HomeView from "@/lib/home/view"
|
||||
|
||||
export default function homePage() {
|
||||
return (
|
||||
<div className="bg-[#F2F8F4] w-full h-screen">
|
||||
<AppBar useLogo/>
|
||||
<HomeView />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user