feat
Desc: - Fitur crowdfunding - Fitur Investasi - Fitur tambah investasi No issue
@@ -12,6 +12,7 @@
|
|||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/server": "^11.11.0",
|
"@emotion/server": "^11.11.0",
|
||||||
"@mantine/core": "^6.0.17",
|
"@mantine/core": "^6.0.17",
|
||||||
|
"@mantine/dropzone": "^7.1.3",
|
||||||
"@mantine/hooks": "^6.0.17",
|
"@mantine/hooks": "^6.0.17",
|
||||||
"@mantine/next": "^6.0.17",
|
"@mantine/next": "^6.0.17",
|
||||||
"@prisma/client": "^5.0.0",
|
"@prisma/client": "^5.0.0",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ model User {
|
|||||||
masterUserRoleId String @default("1")
|
masterUserRoleId String @default("1")
|
||||||
UserSession UserSession?
|
UserSession UserSession?
|
||||||
Profile Profile?
|
Profile Profile?
|
||||||
|
Investasi Investasi[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model MasterUserRole {
|
model MasterUserRole {
|
||||||
@@ -60,12 +61,13 @@ model Profile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Images {
|
model Images {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
url String
|
url String
|
||||||
active Boolean @default(true)
|
active Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Profile Profile?
|
Profile Profile?
|
||||||
|
Investasi Investasi?
|
||||||
}
|
}
|
||||||
|
|
||||||
model Katalog {
|
model Katalog {
|
||||||
@@ -73,12 +75,12 @@ model Katalog {
|
|||||||
namaBisnis String
|
namaBisnis String
|
||||||
alamatKantor String
|
alamatKantor String
|
||||||
tlpn String
|
tlpn String
|
||||||
deskripsi String
|
deskripsi String
|
||||||
active Boolean @default(true)
|
active Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Profile Profile? @relation(fields: [profileId], references: [id])
|
Profile Profile? @relation(fields: [profileId], references: [id])
|
||||||
profileId String?
|
profileId String?
|
||||||
MasterBidangBisnis MasterBidangBisnis @relation(fields: [masterBidangBisnisId], references: [id])
|
MasterBidangBisnis MasterBidangBisnis @relation(fields: [masterBidangBisnisId], references: [id])
|
||||||
masterBidangBisnisId String
|
masterBidangBisnisId String
|
||||||
}
|
}
|
||||||
@@ -91,3 +93,54 @@ model MasterBidangBisnis {
|
|||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Katalog Katalog[]
|
Katalog Katalog[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Investasi {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
title String
|
||||||
|
targetDana String
|
||||||
|
hargaLembar String
|
||||||
|
totalLembar String
|
||||||
|
roi String
|
||||||
|
active Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
author User? @relation(fields: [authorId], references: [id])
|
||||||
|
authorId String?
|
||||||
|
|
||||||
|
MasterPeriodeDeviden MasterPeriodeDeviden? @relation(fields: [masterPeriodeDevidenId], references: [id])
|
||||||
|
masterPeriodeDevidenId String?
|
||||||
|
MasterPembagianDeviden MasterPembagianDeviden? @relation(fields: [masterPembagianDevidenId], references: [id])
|
||||||
|
masterPembagianDevidenId String?
|
||||||
|
MasterPencarianInvestor MasterPencarianInvestor? @relation(fields: [masterPencarianInvestorId], references: [id])
|
||||||
|
masterPencarianInvestorId String?
|
||||||
|
|
||||||
|
ImageInvestasi Images? @relation(fields: [imagesId], references: [id])
|
||||||
|
imagesId String? @unique
|
||||||
|
}
|
||||||
|
|
||||||
|
model MasterPencarianInvestor {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
active Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
investasi Investasi[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model MasterPeriodeDeviden {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
active Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
investasi Investasi[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model MasterPembagianDeviden {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
active Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
investasi Investasi[]
|
||||||
|
}
|
||||||
|
|||||||
BIN
public/aset/no-img.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/investasi/4a673439-52c3-40ce-82fc-a9125083b040.jpeg
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
public/investasi/5b77a1bf-0b2a-47d1-ba6a-adcd8743f80d.jpeg
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
public/investasi/6c716813-1dd4-46b4-be88-06e189121572.png
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
public/investasi/875ba470-cd51-4783-959a-dffb58f0aa3d.jpeg
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
public/investasi/b55259ad-372e-4da0-8988-231574515b71.jpeg
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
public/investasi/c66a818f-45f0-4588-b8fd-22b769196c38.jpeg
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
public/investasi/c8e15676-59ea-480d-b177-6a53defacb55.jpeg
Normal file
|
After Width: | Height: | Size: 439 KiB |
BIN
public/investasi/cecefba0-2061-4598-91dd-b6dbca552b1d.jpeg
Normal file
|
After Width: | Height: | Size: 156 KiB |
39
src/app/api/investasi/gambar/[id]/route.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import fs from "fs";
|
||||||
|
import prisma from "@/app/lib/prisma";
|
||||||
|
|
||||||
|
export async function GET(
|
||||||
|
req: NextRequest,
|
||||||
|
{ params }: { params: { id: string } }
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
console.log(params.id)
|
||||||
|
const data = await prisma.images.findUnique({
|
||||||
|
where: {
|
||||||
|
id: params.id,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
url: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
|
// return data
|
||||||
|
|
||||||
|
if (!fs.existsSync(`./public/investasi/${data?.url}`)) {
|
||||||
|
const fl = fs.readFileSync(`./public/aset/no-img.png`);
|
||||||
|
return new NextResponse(fl, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "image/png",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const fl = fs.readFileSync(`./public/investasi/${data?.url}`);
|
||||||
|
return new NextResponse(fl, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "image/png",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@ import prisma from "@/app/lib/prisma";
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import userRole from "../../../bin/seeder/user_role.json";
|
import userRole from "../../../bin/seeder/user_role.json";
|
||||||
import bidangBisnis from "../../../bin/seeder/bidang_bisnis.json";
|
import bidangBisnis from "../../../bin/seeder/bidang_bisnis.json";
|
||||||
|
import pencarianInvestor from "./../../../bin/seeder/investasi/pencarian_investor.json";
|
||||||
|
import periodeDeviden from "./../../../bin/seeder/investasi/periode_deviden.json";
|
||||||
|
import pembagianDeviden from "./../../../bin/seeder/investasi/pembagian_deviden.json";
|
||||||
|
|
||||||
export async function GET(req: Request) {
|
export async function GET(req: Request) {
|
||||||
const dev = new URL(req.url).searchParams.get("dev");
|
const dev = new URL(req.url).searchParams.get("dev");
|
||||||
@@ -37,6 +40,55 @@ export async function GET(req: Request) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let i of pencarianInvestor) {
|
||||||
|
await prisma.masterPencarianInvestor.upsert({
|
||||||
|
where: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
name: i.name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
name: i.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i of pembagianDeviden) {
|
||||||
|
await prisma.masterPembagianDeviden.upsert({
|
||||||
|
where: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
name: i.name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
name: i.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i of periodeDeviden) {
|
||||||
|
await prisma.masterPeriodeDeviden.upsert({
|
||||||
|
where: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
name: i.name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: i.id.toString(),
|
||||||
|
name: i.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
return NextResponse.json({ success: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
src/app/dev/crowd/main/layout.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { LayoutMainCrowd } from "@/app_modules/crowd";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default async function Layout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutMainCrowd>{children}</LayoutMainCrowd>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
src/app/dev/crowd/main/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { MainCrowd } from "@/app_modules/crowd";
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MainCrowd />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
src/app/dev/crowd/splash/page.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { SplashCrowd } from "@/app_modules/crowd";
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
return <>
|
||||||
|
<SplashCrowd/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
14
src/app/dev/investasi/create/layout.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { InvestasiCreateLayout } from "@/app_modules/investasi";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default async function Layout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InvestasiCreateLayout>{children}</InvestasiCreateLayout>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
37
src/app/dev/investasi/create/page.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { InvestasiCreate } from "@/app_modules/investasi";
|
||||||
|
import { unsealData } from "iron-session";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import yaml from "yaml";
|
||||||
|
import fs from "fs";
|
||||||
|
import { funCreateInvestasi } from "@/app_modules/investasi/fun/fun_create_investasi";
|
||||||
|
import getPencarianInvestor from "@/app_modules/investasi/fun/get_pencarian_investor";
|
||||||
|
import getPeriodeDeviden from "@/app_modules/investasi/fun/get_periode_deviden";
|
||||||
|
import getPembagianDeviden from "@/app_modules/investasi/fun/get_pembagian_deviden";
|
||||||
|
|
||||||
|
const config = yaml.parse(fs.readFileSync("config.yaml").toString());
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
const c = cookies().get("ssn");
|
||||||
|
const tkn = JSON.parse(
|
||||||
|
await unsealData(c?.value as string, {
|
||||||
|
password: config.server.password,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const pencarianInvestor = await getPencarianInvestor();
|
||||||
|
const periodeDeviden = await getPeriodeDeviden();
|
||||||
|
const pembagianDeviden = await getPembagianDeviden();
|
||||||
|
|
||||||
|
// console.log(pembagianDeviden)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InvestasiCreate
|
||||||
|
id={tkn.id}
|
||||||
|
pencarianInvestor={pencarianInvestor as any}
|
||||||
|
periodeDeviden={periodeDeviden as any}
|
||||||
|
pembagianDeviden={pembagianDeviden as any}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
src/app/dev/investasi/main/layout.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { LayoutMainInvestasi } from "@/app_modules/investasi";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default async function Layout({children}: {children: React.ReactNode}) {
|
||||||
|
return <>
|
||||||
|
<LayoutMainInvestasi>{children}</LayoutMainInvestasi>
|
||||||
|
</>
|
||||||
|
}
|
||||||
24
src/app/dev/investasi/main/page.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { MainInvestasi } from "@/app_modules/investasi";
|
||||||
|
import { getListAllInvestasi } from "@/app_modules/investasi/fun/get_list_all_investasi";
|
||||||
|
import getPembagianDeviden from "@/app_modules/investasi/fun/get_pembagian_deviden";
|
||||||
|
import getPencarianInvestor from "@/app_modules/investasi/fun/get_pencarian_investor";
|
||||||
|
import getPeriodeDeviden from "@/app_modules/investasi/fun/get_periode_deviden";
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
const data = await getListAllInvestasi()
|
||||||
|
const pencarianInvestor = await getPencarianInvestor();
|
||||||
|
const periodeDeviden = await getPeriodeDeviden();
|
||||||
|
const pembagianDeviden = await getPembagianDeviden();
|
||||||
|
|
||||||
|
// console.log(data)
|
||||||
|
return <>
|
||||||
|
<MainInvestasi
|
||||||
|
listData={data as any}
|
||||||
|
pencarianInvestor={pencarianInvestor as any}
|
||||||
|
periodeDeviden={periodeDeviden as any}
|
||||||
|
pembagianDeviden={pembagianDeviden as any}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
8
src/app/dev/investasi/upload/layout.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { LayoutUploadGambarInvestasi } from "@/app_modules/investasi";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default async function Layout({children}: {children: React.ReactNode}) {
|
||||||
|
return<>
|
||||||
|
<LayoutUploadGambarInvestasi>{children}</LayoutUploadGambarInvestasi>
|
||||||
|
</>
|
||||||
|
}
|
||||||
7
src/app/dev/investasi/upload/page.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { UploadGambarInvestasi } from "@/app_modules/investasi";
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
return<>
|
||||||
|
<UploadGambarInvestasi/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
@@ -14,4 +14,7 @@ export const ApiHipmi = {
|
|||||||
|
|
||||||
//Portofolio
|
//Portofolio
|
||||||
create_portofolio: "/api/portofolio/create",
|
create_portofolio: "/api/portofolio/create",
|
||||||
|
|
||||||
|
//Investasi
|
||||||
|
get_gambar_investasi: "/api/investasi/gambar"
|
||||||
};
|
};
|
||||||
|
|||||||
54
src/app_modules/component/header_tamplate.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Header, Group, ActionIcon, Text } from "@mantine/core";
|
||||||
|
import { IconArrowLeft } from "@tabler/icons-react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function HeaderTamplate({
|
||||||
|
route,
|
||||||
|
route2,
|
||||||
|
title,
|
||||||
|
icon,
|
||||||
|
}: {
|
||||||
|
route?: any;
|
||||||
|
route2?: any;
|
||||||
|
title: string;
|
||||||
|
icon?: any;
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header height={50}>
|
||||||
|
<Group h={50} position="apart" px={"md"}>
|
||||||
|
<ActionIcon
|
||||||
|
variant="transparent"
|
||||||
|
onClick={() => {
|
||||||
|
if (route === null || route === undefined) {
|
||||||
|
return router.back();
|
||||||
|
} else {
|
||||||
|
return router.push(route);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconArrowLeft />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text>{title}</Text>
|
||||||
|
{(() => {
|
||||||
|
if (route2 === null ||route2 === undefined) {
|
||||||
|
return <ActionIcon disabled variant="transparent"></ActionIcon>;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<ActionIcon
|
||||||
|
variant="transparent"
|
||||||
|
onClick={() => router.push(route2)}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</ActionIcon>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</Group>
|
||||||
|
</Header>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
src/app_modules/crowd/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import MainCrowd from "./main/view";
|
||||||
|
import LayoutMainCrowd from "./main/layout";
|
||||||
|
import SplashCrowd from "./splash/view";
|
||||||
|
|
||||||
|
export {MainCrowd,LayoutMainCrowd, SplashCrowd}
|
||||||
24
src/app_modules/crowd/main/layout.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import HeaderTamplate from "@/app_modules/component/header_tamplate";
|
||||||
|
import { ActionIcon, AppShell, Group, Header, Text } from "@mantine/core";
|
||||||
|
import { IconArrowLeft } from "@tabler/icons-react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function LayoutMainCrowd({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AppShell
|
||||||
|
header={<HeaderTamplate route="/dev/home" title="Crowd Funding" />}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AppShell>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
src/app_modules/crowd/main/view.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Button, Center, Stack, Text, Title } from "@mantine/core";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import toast from "react-simple-toasts";
|
||||||
|
|
||||||
|
export default function MainCrowd() {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Center>
|
||||||
|
<Stack>
|
||||||
|
<Text>Selamat datang di</Text>
|
||||||
|
<Text>HIPMI Crowd Funding</Text>
|
||||||
|
<Button
|
||||||
|
w={300}
|
||||||
|
bg={"green"}
|
||||||
|
onClick={() => router.push("/dev/investasi/main")}
|
||||||
|
>
|
||||||
|
Investasi
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
w={300}
|
||||||
|
bg={"grape"}
|
||||||
|
onClick={() => toast("Cooming Soon Feature...")}
|
||||||
|
>
|
||||||
|
Donasi
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
src/app_modules/crowd/splash/view.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Center, Stack, Text, Title } from "@mantine/core";
|
||||||
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function SplashCrowd() {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
setTimeout(() => router.push("/dev/crowd/main"), 2000);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Center h={"100vh"}>
|
||||||
|
<Stack>
|
||||||
|
<Text>Welcome to,</Text>
|
||||||
|
<Title>CrowdFunding</Title>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -47,48 +47,7 @@ import { funGetUserProfile } from "../fun/get_user_profile";
|
|||||||
import { USER_PROFILE } from "../models/user_profile";
|
import { USER_PROFILE } from "../models/user_profile";
|
||||||
import AppNotif from "../notif";
|
import AppNotif from "../notif";
|
||||||
|
|
||||||
const listHalaman = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "Forums",
|
|
||||||
icon: <IconMessages size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "Project Collaboration",
|
|
||||||
icon: <IconAffiliate size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "Voting",
|
|
||||||
icon: <IconPackageImport size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "Event",
|
|
||||||
icon: <IconPresentation size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "Crowd Funding",
|
|
||||||
icon: <IconHeartHandshake size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: "Marketplace",
|
|
||||||
icon: <IconShoppingBag size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: "Job Vacancy",
|
|
||||||
icon: <IconBriefcase size={50} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: "Business Maps",
|
|
||||||
icon: <IconMap2 size={50} />,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// export const dynamic = "force-dynamic"
|
// export const dynamic = "force-dynamic"
|
||||||
// export const revalidate = 0
|
// export const revalidate = 0
|
||||||
@@ -97,6 +56,64 @@ export default function HomeView({ user }: { user: USER_PROFILE }) {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [stateUser, setStateUser] = useState(user);
|
const [stateUser, setStateUser] = useState(user);
|
||||||
|
|
||||||
|
const listHalaman = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Forums",
|
||||||
|
icon: <IconMessages size={50} />,
|
||||||
|
link: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "Project Collaboration",
|
||||||
|
icon: <IconAffiliate size={50} />,
|
||||||
|
link: ""
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "Voting",
|
||||||
|
icon: <IconPackageImport size={50} />,
|
||||||
|
link: ""
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "Event",
|
||||||
|
icon: <IconPresentation size={50} />,
|
||||||
|
link: ""
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "Crowd Funding",
|
||||||
|
icon: <IconHeartHandshake size={50} />,
|
||||||
|
link: `/dev/crowd/splash`
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "Marketplace",
|
||||||
|
icon: <IconShoppingBag size={50} />,
|
||||||
|
link: ""
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "Job Vacancy",
|
||||||
|
icon: <IconBriefcase size={50} />,
|
||||||
|
link: ""
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: "Business Maps",
|
||||||
|
icon: <IconMap2 size={50} />,
|
||||||
|
link: ""
|
||||||
|
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -134,7 +151,13 @@ export default function HomeView({ user }: { user: USER_PROFILE }) {
|
|||||||
key={e.id}
|
key={e.id}
|
||||||
h={100}
|
h={100}
|
||||||
withBorder
|
withBorder
|
||||||
onClick={() => toast(e.name)}
|
onClick={() => {
|
||||||
|
if(e.link === ""){
|
||||||
|
toast(e.name)
|
||||||
|
} else {
|
||||||
|
return router.push(e.link)
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
justify={"center"}
|
justify={"center"}
|
||||||
|
|||||||
23
src/app_modules/investasi/create/layout.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import HeaderTamplate from "@/app_modules/component/header_tamplate";
|
||||||
|
import { AppShell } from "@mantine/core";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function InvestasiCreateLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AppShell
|
||||||
|
header={
|
||||||
|
<HeaderTamplate route="/dev/investasi/main" title="Investasi Baru" />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AppShell>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
209
src/app_modules/investasi/create/view.tsx
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ApiHipmi } from "@/app/lib/api";
|
||||||
|
import { Warna } from "@/app/lib/warna";
|
||||||
|
import { MODEL_ALL_MASTER } from "@/app_modules/models/model_AllMaster";
|
||||||
|
import {
|
||||||
|
AspectRatio,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
FileButton,
|
||||||
|
Group,
|
||||||
|
Image,
|
||||||
|
Select,
|
||||||
|
TextInput,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import { IconCamera } from "@tabler/icons-react";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { funCreateInvestasi } from "../fun/fun_create_investasi";
|
||||||
|
import toast from "react-simple-toasts";
|
||||||
|
|
||||||
|
export default function InvestasiCreate({
|
||||||
|
id,
|
||||||
|
pencarianInvestor,
|
||||||
|
periodeDeviden,
|
||||||
|
pembagianDeviden,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
pencarianInvestor: MODEL_ALL_MASTER[];
|
||||||
|
periodeDeviden: MODEL_ALL_MASTER[];
|
||||||
|
pembagianDeviden: MODEL_ALL_MASTER[];
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const [fl, setFl] = useState<File | null>(null);
|
||||||
|
const [img, setImg] = useState<any | null>();
|
||||||
|
const [value, setValue] = useState({
|
||||||
|
title: "",
|
||||||
|
targetDana: "",
|
||||||
|
hargaLembar: "",
|
||||||
|
totalLembar: "",
|
||||||
|
roi: "",
|
||||||
|
pencarianInvestorId: "",
|
||||||
|
periodeDevidenId: "",
|
||||||
|
pembagianDevidenId: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
async function onSubmit() {
|
||||||
|
const body = {
|
||||||
|
authorId: id,
|
||||||
|
title: value.title,
|
||||||
|
targetDana: value.targetDana,
|
||||||
|
hargaLembar: value.hargaLembar,
|
||||||
|
totalLembar: value.totalLembar,
|
||||||
|
roi: value.roi,
|
||||||
|
masterPeriodeDevidenId: value.periodeDevidenId,
|
||||||
|
masterPembagianDevidenId: value.pembagianDevidenId,
|
||||||
|
masterPencarianInvestorId: value.pencarianInvestorId,
|
||||||
|
};
|
||||||
|
if (_.values(body).includes("")) return toast("Lengkapi data");
|
||||||
|
if (!fl) return toast("File Kosong");
|
||||||
|
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append("file", fl);
|
||||||
|
|
||||||
|
await funCreateInvestasi(fd, body as any).then((res) => {
|
||||||
|
if (res.status === 201) {
|
||||||
|
toast(res.message);
|
||||||
|
return router.push("/dev/investasi/main")
|
||||||
|
} else {
|
||||||
|
return toast(res.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box>
|
||||||
|
<AspectRatio ratio={16 / 9}>
|
||||||
|
{img ? (
|
||||||
|
<Image alt="" src={img} />
|
||||||
|
) : (
|
||||||
|
<Image alt="" src={"/aset/no-img.png"} />
|
||||||
|
)}
|
||||||
|
</AspectRatio>
|
||||||
|
<Group position="center" mt={"md"}>
|
||||||
|
<FileButton
|
||||||
|
onChange={async (files: any) => {
|
||||||
|
const buffer = URL.createObjectURL(
|
||||||
|
new Blob([new Uint8Array(await files.arrayBuffer())])
|
||||||
|
);
|
||||||
|
setImg(buffer);
|
||||||
|
setFl(files);
|
||||||
|
}}
|
||||||
|
accept="image/png,image/jpeg"
|
||||||
|
>
|
||||||
|
{(props) => (
|
||||||
|
<Button
|
||||||
|
{...props}
|
||||||
|
w={350}
|
||||||
|
radius={50}
|
||||||
|
// bg={Warna.biru}
|
||||||
|
// onClick={() => router.push("/dev/investasi/upload")}
|
||||||
|
>
|
||||||
|
<IconCamera />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</FileButton>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Center>
|
||||||
|
<Box mt={"md"} w={350}>
|
||||||
|
<TextInput
|
||||||
|
label="Judul Proyek"
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
title: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Dana Dibutuhan"
|
||||||
|
type="number"
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
targetDana: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Harga Per Lember"
|
||||||
|
type="number"
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
hargaLembar: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Total Lembar"
|
||||||
|
type="number"
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
totalLembar: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Rasio Keuntungan / ROI"
|
||||||
|
type="number"
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
roi: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Pencarian Investor"
|
||||||
|
data={pencarianInvestor.map((e) => ({
|
||||||
|
value: e.id,
|
||||||
|
label: e.name,
|
||||||
|
}))}
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...(value as any),
|
||||||
|
pencarianInvestorId: val,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Periode Deviden"
|
||||||
|
data={periodeDeviden.map((e) => ({ value: e.id, label: e.name }))}
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...(value as any),
|
||||||
|
periodeDevidenId: val,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Pembagian Deviden"
|
||||||
|
data={pembagianDeviden.map((e) => ({
|
||||||
|
value: e.id,
|
||||||
|
label: e.name,
|
||||||
|
}))}
|
||||||
|
onChange={(val) => {
|
||||||
|
setValue({
|
||||||
|
...(value as any),
|
||||||
|
pembagianDevidenId: val,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Center>
|
||||||
|
<Center my={"lg"}>
|
||||||
|
<Button w={200} radius={50} onClick={() => onSubmit()}>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
74
src/app_modules/investasi/fun/fun_create_investasi.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import prisma from "@/app/lib/prisma";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { v4 } from "uuid";
|
||||||
|
import fs from "fs";
|
||||||
|
import { INVESTASI } from "@/app_modules/models/investasi";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
|
||||||
|
export async function funCreateInvestasi(formData: FormData, data: INVESTASI) {
|
||||||
|
const file: any = formData.get("file");
|
||||||
|
// console.log(file)
|
||||||
|
const fName = file.name;
|
||||||
|
const fExt = _.lowerCase(file.name.split(".").pop());
|
||||||
|
const fRandomName = v4(fName) + "." + fExt;
|
||||||
|
|
||||||
|
const upload = await prisma.images.create({
|
||||||
|
data: {
|
||||||
|
url: fRandomName,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
url: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!upload)
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
message: "File Kosong",
|
||||||
|
};
|
||||||
|
|
||||||
|
// if (upload) {
|
||||||
|
// await prisma.investasi.update({
|
||||||
|
// where: {
|
||||||
|
// authorId: data.authorId,
|
||||||
|
// },
|
||||||
|
// data: {
|
||||||
|
// imagesId: upload.id,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
const upFolder = Buffer.from(await file.arrayBuffer());
|
||||||
|
fs.writeFileSync(`./public/investasi/${upload.url}`, upFolder);
|
||||||
|
|
||||||
|
const createInvest = await prisma.investasi.create({
|
||||||
|
data: {
|
||||||
|
authorId: data.authorId,
|
||||||
|
title: data.title,
|
||||||
|
targetDana: data.targetDana,
|
||||||
|
hargaLembar: data.hargaLembar,
|
||||||
|
totalLembar: data.totalLembar,
|
||||||
|
roi: data.roi,
|
||||||
|
masterPembagianDevidenId: data.masterPembagianDevidenId,
|
||||||
|
masterPeriodeDevidenId: data.masterPeriodeDevidenId,
|
||||||
|
masterPencarianInvestorId: data.masterPencarianInvestorId,
|
||||||
|
imagesId: upload.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!createInvest)
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
message: "Gagal Disimpan",
|
||||||
|
};
|
||||||
|
|
||||||
|
revalidatePath("/dev/investasi/main");
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 201,
|
||||||
|
message: "Berhasil Disimpan",
|
||||||
|
};
|
||||||
|
}
|
||||||
13
src/app_modules/investasi/fun/get_list_all_investasi.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import prisma from "@/app/lib/prisma";
|
||||||
|
|
||||||
|
export async function getListAllInvestasi() {
|
||||||
|
const data = await prisma.investasi.findMany({
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
15
src/app_modules/investasi/fun/get_pembagian_deviden.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import prisma from "@/app/lib/prisma";
|
||||||
|
|
||||||
|
export default async function getPembagianDeviden() {
|
||||||
|
const data = await prisma.masterPembagianDeviden.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
15
src/app_modules/investasi/fun/get_pencarian_investor.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import prisma from "@/app/lib/prisma";
|
||||||
|
|
||||||
|
export default async function getPencarianInvestor() {
|
||||||
|
const data = await prisma.masterPencarianInvestor.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
active: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
15
src/app_modules/investasi/fun/get_periode_deviden.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import prisma from "@/app/lib/prisma";
|
||||||
|
|
||||||
|
export default async function getPeriodeDeviden() {
|
||||||
|
const data = await prisma.masterPeriodeDeviden.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
15
src/app_modules/investasi/index.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import MainInvestasi from "./main/view";
|
||||||
|
import LayoutMainInvestasi from "./main/layout";
|
||||||
|
import InvestasiCreate from "./create/view";
|
||||||
|
import InvestasiCreateLayout from "./create/layout";
|
||||||
|
import UploadGambarInvestasi from "./upload/view";
|
||||||
|
import LayoutUploadGambarInvestasi from "./upload/layout";
|
||||||
|
|
||||||
|
export {
|
||||||
|
MainInvestasi,
|
||||||
|
LayoutMainInvestasi,
|
||||||
|
InvestasiCreate,
|
||||||
|
InvestasiCreateLayout,
|
||||||
|
UploadGambarInvestasi,
|
||||||
|
LayoutUploadGambarInvestasi,
|
||||||
|
};
|
||||||
69
src/app_modules/investasi/main/layout.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import HeaderTamplate from "@/app_modules/component/header_tamplate";
|
||||||
|
import {
|
||||||
|
ActionIcon,
|
||||||
|
AppShell,
|
||||||
|
Center,
|
||||||
|
Flex,
|
||||||
|
Footer,
|
||||||
|
Grid,
|
||||||
|
Group,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import {
|
||||||
|
IconChartHistogram,
|
||||||
|
IconChartPieFilled,
|
||||||
|
IconPencilPlus,
|
||||||
|
} from "@tabler/icons-react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function LayoutMainInvestasi({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AppShell
|
||||||
|
header={
|
||||||
|
<HeaderTamplate
|
||||||
|
route="/dev/crowd/main"
|
||||||
|
title="Investasi"
|
||||||
|
icon={<IconPencilPlus />}
|
||||||
|
route2={"/dev/investasi/create"}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
footer={
|
||||||
|
<Footer height={70} bg={"dark"}>
|
||||||
|
<Grid align="center" h={60} pt={"xs"}>
|
||||||
|
<Grid.Col span={6}>
|
||||||
|
<Center>
|
||||||
|
<Flex direction={"column"} align={"center"} w={"100%"}>
|
||||||
|
<ActionIcon variant="transparent">
|
||||||
|
<IconChartHistogram />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text c={"white"}>Bursa</Text>
|
||||||
|
</Flex>
|
||||||
|
</Center>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={6}>
|
||||||
|
<Center>
|
||||||
|
<Flex direction={"column"} align={"center"} w={"100%"}>
|
||||||
|
<ActionIcon variant="transparent">
|
||||||
|
<IconChartPieFilled />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text c={"white"}>Portofolio</Text>
|
||||||
|
</Flex>
|
||||||
|
</Center>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Footer>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AppShell>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
104
src/app_modules/investasi/main/view.tsx
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ApiHipmi } from "@/app/lib/api";
|
||||||
|
import { INVESTASI } from "@/app_modules/models/investasi";
|
||||||
|
import { MODEL_ALL_MASTER } from "@/app_modules/models/model_AllMaster";
|
||||||
|
import {
|
||||||
|
AspectRatio,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardSection,
|
||||||
|
Divider,
|
||||||
|
Grid,
|
||||||
|
Group,
|
||||||
|
Image,
|
||||||
|
Paper,
|
||||||
|
Slider,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
Title,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function MainInvestasi({
|
||||||
|
listData,
|
||||||
|
pencarianInvestor,
|
||||||
|
periodeDeviden,
|
||||||
|
pembagianDeviden,
|
||||||
|
}: {
|
||||||
|
listData: INVESTASI[];
|
||||||
|
pencarianInvestor: MODEL_ALL_MASTER[];
|
||||||
|
periodeDeviden: MODEL_ALL_MASTER[];
|
||||||
|
pembagianDeviden: MODEL_ALL_MASTER[];
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<pre>{/* {JSON.stringify(listData, null, 2)} */}</pre>
|
||||||
|
{listData.map((e) => (
|
||||||
|
<Card key={e.id} p={"md"} withBorder mb={"lg"}>
|
||||||
|
<CardSection p={"xs"}>
|
||||||
|
<AspectRatio ratio={16 / 9}>
|
||||||
|
{e.imagesId ? (
|
||||||
|
<Image alt="" src={`/api/investasi/gambar/${e.imagesId}`} />
|
||||||
|
) : (
|
||||||
|
<Image alt="" src={"/aset/no-img.png"} />
|
||||||
|
)}
|
||||||
|
</AspectRatio>
|
||||||
|
</CardSection>
|
||||||
|
|
||||||
|
<CardSection p={"lg"}>
|
||||||
|
<Box mt={"md"}>
|
||||||
|
<Slider
|
||||||
|
size={10}
|
||||||
|
labelAlwaysOn
|
||||||
|
marks={[
|
||||||
|
// { value: 25, label: '25%' },
|
||||||
|
// { value: 50, label: '50%' },
|
||||||
|
// { value: 75, label: '75%' },
|
||||||
|
{ value: 100, label: "100%" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Title order={4}>{e.title}</Title>
|
||||||
|
</Box>
|
||||||
|
<Box mt={"md"}>
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col span={6}>
|
||||||
|
<Stack>
|
||||||
|
<Box>
|
||||||
|
<Text>Dana Dibutuhkan</Text>
|
||||||
|
<Text>Rp. {e.targetDana}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text>Harga Per Lembar</Text>
|
||||||
|
<Text>Rp. {e.hargaLembar}</Text>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={6}>
|
||||||
|
<Stack>
|
||||||
|
<Box>
|
||||||
|
<Text>ROI</Text>
|
||||||
|
<Text>{e.roi}%</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text>Total Lembar</Text>
|
||||||
|
<Text>{e.totalLembar}</Text>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</CardSection>
|
||||||
|
<Divider />
|
||||||
|
<CardSection p={"md"}>
|
||||||
|
<Group position="right">
|
||||||
|
<Text>Selesai</Text>
|
||||||
|
</Group>
|
||||||
|
</CardSection>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
src/app_modules/investasi/upload/layout.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import HeaderTamplate from "@/app_modules/component/header_tamplate";
|
||||||
|
import { AppShell } from "@mantine/core";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function LayoutUploadGambarInvestasi({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AppShell header={<HeaderTamplate title="Upload Gambar Investasi" />}>
|
||||||
|
{children}
|
||||||
|
</AppShell>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
39
src/app_modules/investasi/upload/view.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Warna } from "@/app/lib/warna";
|
||||||
|
import {
|
||||||
|
AspectRatio,
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
Divider,
|
||||||
|
FileButton,
|
||||||
|
Group,
|
||||||
|
Image,
|
||||||
|
Paper,
|
||||||
|
Text,
|
||||||
|
Title,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function UploadGambarInvestasi() {
|
||||||
|
const [img, setImg] = useState<any | null>();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Group position="center">
|
||||||
|
<FileButton
|
||||||
|
onChange={async (files : any) => {
|
||||||
|
const buffer = URL.createObjectURL(
|
||||||
|
new Blob([new Uint8Array( await files.arrayBuffer())])
|
||||||
|
);
|
||||||
|
setImg(buffer);
|
||||||
|
}}
|
||||||
|
accept="image/png,image/jpeg"
|
||||||
|
>
|
||||||
|
{(props) => <Button {...props}>Upload image</Button>}
|
||||||
|
</FileButton>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{img && <Image alt="" src={img}/>}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
src/app_modules/models/investasi.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export interface INVESTASI {
|
||||||
|
id: string
|
||||||
|
authorId: string;
|
||||||
|
title: string;
|
||||||
|
targetDana: string;
|
||||||
|
hargaLembar: string;
|
||||||
|
totalLembar: string;
|
||||||
|
roi: string;
|
||||||
|
masterPeriodeDevidenId: string;
|
||||||
|
masterPembagianDevidenId: string;
|
||||||
|
masterPencarianInvestorId: string;
|
||||||
|
imagesId: string
|
||||||
|
}
|
||||||
5
src/app_modules/models/model_AllMaster.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface MODEL_ALL_MASTER {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
active: boolean,
|
||||||
|
}
|
||||||
14
src/bin/seeder/investasi/pembagian_deviden.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "3 bulan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "6 bulan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "1 tahun"
|
||||||
|
}
|
||||||
|
]
|
||||||
19
src/bin/seeder/investasi/pencarian_investor.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "30 hari"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "60 hari"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "90 hari"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "120 hari"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
10
src/bin/seeder/investasi/periode_deviden.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Selamanya"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Satu tahun"
|
||||||
|
}
|
||||||
|
]
|
||||||
14
yarn.lock
@@ -287,6 +287,13 @@
|
|||||||
react-remove-scroll "^2.5.5"
|
react-remove-scroll "^2.5.5"
|
||||||
react-textarea-autosize "8.3.4"
|
react-textarea-autosize "8.3.4"
|
||||||
|
|
||||||
|
"@mantine/dropzone@^7.1.3":
|
||||||
|
version "7.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-7.1.3.tgz#02851a45fc7278b63f8b628f0fc35f75a6650563"
|
||||||
|
integrity sha512-7MnXTtlQlL9Q0GluRUKv8AWFDfPv7jv74K+F08Y5bKiQHYR8OzIW4Pc+Vk4Ea9I8/EzoKLWarF0Bn2KkgoO4Lw==
|
||||||
|
dependencies:
|
||||||
|
react-dropzone-esm "15.0.1"
|
||||||
|
|
||||||
"@mantine/hooks@^6.0.17":
|
"@mantine/hooks@^6.0.17":
|
||||||
version "6.0.17"
|
version "6.0.17"
|
||||||
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.17.tgz#dc942c87e6dcfa14a70e4e4a162c22eeb4ff3724"
|
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.17.tgz#dc942c87e6dcfa14a70e4e4a162c22eeb4ff3724"
|
||||||
@@ -2913,6 +2920,13 @@ react-dom@18.2.0:
|
|||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
scheduler "^0.23.0"
|
scheduler "^0.23.0"
|
||||||
|
|
||||||
|
react-dropzone-esm@15.0.1:
|
||||||
|
version "15.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-dropzone-esm/-/react-dropzone-esm-15.0.1.tgz#8c689638aaa9feb5b2a429dd565acfa6792263e5"
|
||||||
|
integrity sha512-RdeGpqwHnoV/IlDFpQji7t7pTtlC2O1i/Br0LWkRZ9hYtLyce814S71h5NolnCZXsIN5wrZId6+8eQj2EBnEzg==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.8.1"
|
||||||
|
|
||||||
react-is@^16.13.1, react-is@^16.7.0:
|
react-is@^16.13.1, react-is@^16.7.0:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
|
|||||||