Merge pull request #241 from bipproduction/join

Fix function upload image & API
This commit is contained in:
Bagasbanuna02
2025-01-16 12:31:06 +08:00
committed by GitHub
88 changed files with 2353 additions and 2468 deletions

View File

@@ -2,6 +2,8 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
## [1.2.40](https://github.com/bipproduction/hipmi/compare/v1.2.39...v1.2.40) (2025-01-16)
## [1.2.39](https://github.com/bipproduction/hipmi/compare/v1.2.38...v1.2.39) (2025-01-12) ## [1.2.39](https://github.com/bipproduction/hipmi/compare/v1.2.38...v1.2.39) (2025-01-12)
## [1.2.38](https://github.com/bipproduction/hipmi/compare/v1.2.37...v1.2.38) (2025-01-03) ## [1.2.38](https://github.com/bipproduction/hipmi/compare/v1.2.37...v1.2.38) (2025-01-03)

View File

@@ -1,16 +1,16 @@
{ {
"name": "hipmi", "name": "hipmi",
"version": "1.2.39", "version": "1.2.40",
"private": true, "private": true,
"prisma": { "prisma": {
"seed": "npx tsx prisma/seed.ts --yes" "seed": "bun prisma/seed.ts"
}, },
"scripts": { "scripts": {
"dev": "bun --bun run next dev --experimental-https", "dev": "next dev --experimental-https",
"build": "NODE_OPTIONS='--max-old-space-size=2048' bun --bun run next build", "build": "next build",
"build:dev": "bun --bun run next build", "build:dev": "next build",
"start": "bun --bun run next start", "start": "next start",
"lint": "bun --bun run next lint", "lint": "next lint",
"ver": "bunx commit-and-tag-version -- --prerelease" "ver": "bunx commit-and-tag-version -- --prerelease"
}, },
"dependencies": { "dependencies": {

View File

@@ -3,18 +3,18 @@ import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import sharp from "sharp"; import sharp from "sharp";
export async function POST(request: Request) { export async function POST(request: Request) {
let fixFormData;
const formData = await request.formData(); const formData = await request.formData();
const file: any = formData.get("file");
const mimeType = file.type;
console.log("MIME Type:", mimeType);
const valueOfDir = formData.get("dirId"); const valueOfDir = formData.get("dirId");
const keyOfDirectory = await funGetDirectoryNameByValue({ const keyOfDirectory = await funGetDirectoryNameByValue({
value: valueOfDir as string, value: valueOfDir as string,
}); });
if (request.method === "POST") { if (request.method === "POST") {
let fixFormData;
const file: any = formData.get("file");
const mimeType = file.type;
// console.log("MIME Type:", mimeType);
try { try {
if (mimeType != "application/pdf") { if (mimeType != "application/pdf") {
// Resize ukuran // Resize ukuran

View File

@@ -2,38 +2,48 @@ import { prisma } from "@/app/lib";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
// GET ONE DATA INVESTASI BY ID // GET ONE DATA INVESTASI BY ID
export async function GET(request: Request, context: { params: { id: string } }) { export async function GET(
try { request: Request,
const { id } = context.params context: { params: { id: string } }
const data = await prisma.investasi.findUnique({ ) {
where: { try {
id: id, const { id } = context.params;
}, const data = await prisma.investasi.findUnique({
select: { where: {
id: true, id: id,
title: true, },
targetDana: true, include: {
hargaLembar: true, author: {
totalLembar: true, include: {
roi: true, Profile: true,
countDown: true, },
catatan: true, },
sisaLembar: true, Investasi_Invoice: true,
imageId: true, MasterStatusInvestasi: true,
masterPencarianInvestorId: true, BeritaInvestasi: true,
masterPeriodeDevidenId: true, DokumenInvestasi: true,
masterPembagianDevidenId: true, ProspektusInvestasi: true,
} MasterPembagianDeviden: true,
}); MasterPencarianInvestor: true,
MasterPeriodeDeviden: true,
MasterProgresInvestasi: true,
},
});
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data }, { status: 200 }); return NextResponse.json(
{ success: true, message: "Berhasil mendapatkan data", data },
} { status: 200 }
catch (error) { );
console.error(error); } catch (error) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan data, coba lagi nanti ", reason: (error as Error).message, }, { status: 500 }); console.error(error);
} return NextResponse.json(
} {
success: false,
message: "Gagal mendapatkan data, coba lagi nanti ",
reason: (error as Error).message,
},
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,85 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server";
export async function GET(
request: Request,
context: { params: { id: string } }
) {
// if (request.method === "GET") {
// return NextResponse.json(
// { success: false, message: "Method not allowed" },
// { status: 405 }
// );
// }
try {
let fixData;
const { id } = context.params;
const { searchParams } = new URL(request.url);
const kategori: string | null = searchParams.get("kategori");
const page = searchParams.get("page");
const takeData = 10;
const skipData = Number(page) * takeData - takeData;
if (!kategori) {
fixData = await prisma.beritaInvestasi.findFirst({
where: {
id: id,
},
include: {
investasi: {
select: {
authorId: true,
},
},
},
});
} else if (kategori == "get-all") {
fixData = await prisma.beritaInvestasi.findMany({
take: takeData,
skip: skipData,
orderBy: {
updatedAt: "desc",
},
where: {
investasiId: id,
active: true,
},
});
}
await prisma.$disconnect();
return NextResponse.json(
{ success: true, message: "Success get data news", data: fixData },
{ status: 200 }
);
} catch (error) {
await prisma.$disconnect();
backendLogger.error("Error get data news", error);
return NextResponse.json(
{
success: false,
message: "Failed to get data, try again later",
reason: (error as Error).message,
},
{ status: 500 }
);
}
}
async function main({ id }: { id: string }) {
const fixData = await prisma.beritaInvestasi.findMany({
take: 10,
skip: 0,
orderBy: {
updatedAt: "desc",
},
where: {
investasiId: id.trim(),
active: true,
},
});
console.log("data sebelum disconnect>>", fixData);
}

View File

@@ -0,0 +1,61 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server";
export async function GET(
request: Request,
context: { params: { id: string } }
) {
if (request.method === "GET") {
try {
let fixData;
const { id } = context.params;
const { searchParams } = new URL(request.url);
const kategori = searchParams.get("kategori");
const page = searchParams.get("page");
const takeData = 10;
const skipData = Number(page) * takeData - takeData;
if (kategori == null) {
fixData = await prisma.dokumenInvestasi.findFirst({
where: {
id: id,
},
});
} else if (kategori == "get-all") {
fixData = await prisma.dokumenInvestasi.findMany({
take: takeData,
skip: skipData,
orderBy: {
updatedAt: "desc",
},
where: {
investasiId: id,
active: true,
},
});
}
await prisma.$disconnect();
return NextResponse.json(
{ success: true, message: "Success get data document", data: fixData },
{ status: 200 }
);
} catch (error) {
backendLogger.error("Error get data document", error);
return NextResponse.json(
{
success: false,
message: "Failed to get data, try again later",
reason: (error as Error).message,
},
{ status: 500 }
);
}
}
return NextResponse.json(
{ success: false, message: "Method not allowed" },
{ status: 405 }
);
}

View File

@@ -1,9 +1,6 @@
import { DIRECTORY_ID, prisma } from "@/app/lib"; import { prisma } from "@/app/lib";
import { NextResponse } from "next/server";
import fs from "fs";
import { funGlobal_DeleteFileById } from "@/app_modules/_global/fun";
import { apiDeleteImageById } from "@/app_modules/_global/lib/api_image";
import backendLogger from "@/util/backendLogger"; import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
// GET ONE DATA PORTOFOLIO BY ID PORTOFOLIO // GET ONE DATA PORTOFOLIO BY ID PORTOFOLIO

View File

@@ -1,12 +1,12 @@
import { investasi_funGetOneBeritaById } from "@/app_modules/investasi/_fun"; import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { Investasi_UiDetailBerita } from "@/app_modules/investasi/_ui"; import { Investasi_UiDetailBerita } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const beritaId = params.id; const userLoginId = await funGetUserIdByToken();
const dataBerita = await investasi_funGetOneBeritaById({ beritaId });
return ( return (
<> <>
<Investasi_UiDetailBerita dataBerita={dataBerita} /> <Investasi_UiDetailBerita userLoginId={userLoginId} />
</> </>
); );
} }

View File

@@ -1,14 +1,9 @@
import { investasi_funGetBeritaById } from "@/app_modules/investasi/_fun";
import { Investasi_UiDaftarBerita } from "@/app_modules/investasi/_ui"; import { Investasi_UiDaftarBerita } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
const dataBerita = await investasi_funGetBeritaById({ investasiId });
return ( return (
<> <>
<Investasi_UiDaftarBerita dataBerita={dataBerita} /> <Investasi_UiDaftarBerita />
</> </>
); );
} }

View File

@@ -1,17 +1,9 @@
import { investasi_funGetBeritaById } from "@/app_modules/investasi/_fun";
import { Investasi_UiRekapBerita } from "@/app_modules/investasi/_ui"; import { Investasi_UiRekapBerita } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
const dataBerita = await investasi_funGetBeritaById({ investasiId });
return ( return (
<> <>
<Investasi_UiRekapBerita <Investasi_UiRekapBerita />
investasiId={investasiId}
dataBerita={dataBerita}
/>
</> </>
); );
} }

View File

@@ -1,10 +1,9 @@
import { Investasi_UiCreateBerita } from "@/app_modules/investasi/_ui"; import { Investasi_UiCreateBerita } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
return ( return (
<> <>
<Investasi_UiCreateBerita investasiId={investasiId} /> <Investasi_UiCreateBerita />
</> </>
); );
} }

View File

@@ -1,11 +1,9 @@
import { Investasi_UiCreateDocument } from "@/app_modules/investasi/_ui"; import { Investasi_UiCreateDocument } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
return ( return (
<> <>
<Investasi_UiCreateDocument investasiId={investasiId} /> <Investasi_UiCreateDocument />
</> </>
); );
} }

View File

@@ -1,21 +1,9 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { investasi_funGetOneInvestasiById } from "@/app_modules/investasi/_fun";
import { Investasi_UiDetailPortofolio } from "@/app_modules/investasi/_ui"; import { Investasi_UiDetailPortofolio } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
const userLoginId = await funGetUserIdByToken();
const dataPortofolio = await investasi_funGetOneInvestasiById({
investasiId,
});
return ( return (
<> <>
<Investasi_UiDetailPortofolio <Investasi_UiDetailPortofolio />
dataInvestasi={dataPortofolio as any}
userLoginId={userLoginId as string}
/>
</> </>
); );
} }

View File

@@ -1,21 +1,9 @@
import {
investasi_funGetAllDocumentById
} from "@/app_modules/investasi/_fun";
import { Investasi_UiDaftarDokmen } from "@/app_modules/investasi/_ui"; import { Investasi_UiDaftarDokmen } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
const dataDokumen = await investasi_funGetAllDocumentById({
investasiId: investasiId,
page: 1,
});
return ( return (
<> <>
<Investasi_UiDaftarDokmen <Investasi_UiDaftarDokmen />
dataDokumen={dataDokumen}
investasiId={investasiId}
/>
</> </>
); );
} }

View File

@@ -1,19 +1,9 @@
import { investasi_funGetAllDocumentById } from "@/app_modules/investasi/_fun";
import { Investasi_UiRekapDokumen } from "@/app_modules/investasi/_ui"; import { Investasi_UiRekapDokumen } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
const dataDokumen = await investasi_funGetAllDocumentById({
investasiId,
page: 1,
});
return ( return (
<> <>
<Investasi_UiRekapDokumen <Investasi_UiRekapDokumen />
investasiId={investasiId}
dataDokumen={dataDokumen}
/>
</> </>
); );
} }

View File

@@ -1,38 +1,8 @@
import { investasi_funGetOneInvestasiById } from "@/app_modules/investasi/_fun"; import { Investasi_UiEditInvestasiNew } from "@/app_modules/investasi/_ui";
import { Investasi_UiEditInvestasi, Investasi_UiEditInvestasiNew } from "@/app_modules/investasi/_ui";
import getPembagianDeviden from "@/app_modules/investasi/fun/master/get_pembagian_deviden";
import getPencarianInvestor from "@/app_modules/investasi/fun/master/get_pencarian_investor";
import getPeriodeDeviden from "@/app_modules/investasi/fun/master/get_periode_deviden";
import _ from "lodash";
export default async function Page({ params }: { params: { id: string } }) {
// const investasiId = params.id;
// const allData = await investasi_funGetOneInvestasiById({ investasiId });
// const dataInvestasi = _.omit(allData, [
// "BeritaInvestasi",
// "DokumenInvestasi",
// "MasterPembagianDeviden",
// "MasterPencarianInvestor",
// "MasterProgresInvestasi",
// "MasterStatusInvestasi",
// "ProspektusInvestasi",
// "MasterPeriodeDeviden",
// "author",
// ]);
// const listPencarian = await getPencarianInvestor();
// const listPeriode = await getPeriodeDeviden();
// const listPembagian = await getPembagianDeviden();
export default async function Page() {
return ( return (
<> <>
{/* <Investasi_UiEditInvestasi
dataInvestasi={dataInvestasi}
pembagianDeviden={listPembagian}
pencarianInvestor={listPencarian}
periodeDeviden={listPeriode}
/> */}
<Investasi_UiEditInvestasiNew /> <Investasi_UiEditInvestasiNew />
</> </>
); );

View File

@@ -1,14 +1,9 @@
import { investasi_funGetOneDocumentById } from "@/app_modules/investasi/_fun";
import { Investasi_UiEditDokumen } from "@/app_modules/investasi/_ui"; import { Investasi_UiEditDokumen } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const documentId = params.id;
const dataDokumen = await investasi_funGetOneDocumentById({ documentId });
return ( return (
<> <>
<Investasi_UiEditDokumen dataDokumen={dataDokumen} /> <Investasi_UiEditDokumen/>
</> </>
); );
} }

View File

@@ -1,11 +1,10 @@
import { Investasi_UiEditProspektus } from "@/app_modules/investasi/_ui"; import { Investasi_UiEditProspektus } from "@/app_modules/investasi/_ui";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
const investasiId = params.id;
return ( return (
<> <>
<Investasi_UiEditProspektus investasiId={investasiId} /> <Investasi_UiEditProspektus />
</> </>
); );
} }

View File

@@ -1,8 +0,0 @@
import { LayoutEditDokumenInvestasi } from "@/app_modules/investasi";
import React from "react";
export default async function Layout({children, params}: {children: React.ReactNode, params: {id: string}}) {
return<>
<LayoutEditDokumenInvestasi idInves={params.id}>{children}</LayoutEditDokumenInvestasi>
</>
}

View File

@@ -1,10 +0,0 @@
import { EditDokumenInvestasi } from "@/app_modules/investasi";
import getOneInvestasiById from "@/app_modules/investasi/fun/get_one_investasi_by_id";
export default async function Page({params}: {params: {id: string}}) {
const dataInvestasi = await getOneInvestasiById(params.id)
// console.log(dataInvestasi)
return<>
<EditDokumenInvestasi dataInvestasi={dataInvestasi as any} />
</>
}

View File

@@ -1,21 +0,0 @@
import { LayoutEditProspektusInvestasi } from "@/app_modules/investasi";
import getOneInvestasiById from "@/app_modules/investasi/fun/get_one_investasi_by_id";
import React from "react";
export default async function Layout({
children,
params,
}: {
children: React.ReactNode;
params: { id: string };
}) {
const dataInvestasi = await getOneInvestasiById(params.id);
return (
<>
<LayoutEditProspektusInvestasi dataInvestasi={dataInvestasi as any}>
{children}
</LayoutEditProspektusInvestasi>
</>
);
}

View File

@@ -1,12 +0,0 @@
import { EditProspektusInvestasi } from "@/app_modules/investasi";
import getOneInvestasiById from "@/app_modules/investasi/fun/get_one_investasi_by_id";
export default async function Page({ params }: { params: { id: string } }) {
const dataInvestasi = await getOneInvestasiById(params.id);
// console.log(dataInvestasi);
return (
<>
<EditProspektusInvestasi dataInvestasi={dataInvestasi as any} />
</>
);
}

View File

@@ -1,6 +1,6 @@
const DIRECTORY_ID = { const DIRECTORY_ID = {
profile_foto: "cm5ni43ub001pxpug0qw4p11e", profile_foto: "cm0x93rgo000jbp5tj8baoaus",
profile_background: "cm5ni4hnq001l12p9gpagxgtv", profile_background: "cm0x93ze8000lbp5t1a8uc9wl",
portofolio_logo: "cm0yjl6ug000310njwmk6j0tx", portofolio_logo: "cm0yjl6ug000310njwmk6j0tx",
map_pin: "cm0yjq8up000710njv5klra32", map_pin: "cm0yjq8up000710njv5klra32",
map_image: "cm0yjqnxl000910njplqho07w", map_image: "cm0yjqnxl000910njplqho07w",

View File

@@ -1,3 +1,4 @@
import { useDisclosure } from "@mantine/hooks";
import { PrismaClient } from "@prisma/client"; import { PrismaClient } from "@prisma/client";
// Singleton PrismaClient untuk pengembangan // Singleton PrismaClient untuk pengembangan
@@ -20,8 +21,9 @@ if (process.env.NODE_ENV !== "production") {
} }
process.on("SIGINT", async () => { process.on("SIGINT", async () => {
console.log("Disconnecting PrismaClient..."); // console.log("Start in Disconnecting PrismaClient...");
await prisma.$disconnect();3 const disconnect = await prisma.$disconnect();
// console.log("End of Disconnecting PrismaClient...", disconnect);
process.exit(0); process.exit(0);
}); });

View File

@@ -1,52 +0,0 @@
"use server";
import _ from "lodash";
// import { v4 } from "uuid";
import fs from "fs";
import sharp from "sharp";
export default async function fun_upload({
file,
dirId,
}: {
file: File;
dirId: string;
}) {
// const file: any = formData.get("file");
// const fName = file.name;
// const fileSize = file.size;
// // Convert ke KB
// const fileSizeInKB = fileSize / 1024;
// // Convert ke MB
// const fileSizeInMB = fileSize / (1024 * 1024);
// console.log(`Ukuran file dalam bytes: ${fileSize}`);
// console.log(`Ukuran file dalam KB: ${fileSizeInKB.toFixed(2)} KB`);
// console.log(`Ukuran file dalam MB: ${fileSizeInMB.toFixed(2)} MB`);
const imageBuffer = await file.arrayBuffer();
const resize = await sharp(imageBuffer).resize(2000).toBuffer();
const newFile = Buffer.from(resize);
console.log("file new",newFile);
// fs.writeFileSync(`./public/upload/${fName}`, upFolder as any);
const formData = new FormData();
formData.append("file", file);
formData.append("dirId", dirId);
// const upload = await fetch("/api/image/upload", {
// method: "POST",
// body: formData,
// });
// const res = await upload.json();
// if (upload.ok) {
// return { success: true, data: res.data, message: res.message };
// } else {
// return { success: false, data: {}, message: res.message };
// }
}

View File

@@ -2,9 +2,7 @@
import { MainColor } from "@/app_modules/_global/color"; import { MainColor } from "@/app_modules/_global/color";
import { ComponentGlobal_BoxUploadImage } from "@/app_modules/_global/component"; import { ComponentGlobal_BoxUploadImage } from "@/app_modules/_global/component";
import { MAX_SIZE } from "@/app_modules/_global/lib"; import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
import { import {
UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutHeaderTamplate,
UIGlobal_LayoutTamplate, UIGlobal_LayoutTamplate,
@@ -20,8 +18,6 @@ import {
} from "@mantine/core"; } from "@mantine/core";
import { IconImageInPicture, IconUpload } from "@tabler/icons-react"; import { IconImageInPicture, IconUpload } from "@tabler/icons-react";
import { useState } from "react"; import { useState } from "react";
import fun_upload from "./fun_upload";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
export default function Page() { export default function Page() {
return ( return (

View File

@@ -2,16 +2,23 @@
import { clientLogger } from "@/util/clientLogger"; import { clientLogger } from "@/util/clientLogger";
import { Button, FileButton } from "@mantine/core"; import { Button, FileButton } from "@mantine/core";
import { IconCamera } from "@tabler/icons-react"; import { IconUpload } from "@tabler/icons-react";
import { useState } from "react"; import { useState } from "react";
import { MainColor } from "../color"; import { AccentColor, MainColor } from "../color";
import { ComponentGlobal_NotifikasiPeringatan } from "../notif_global";
export function ComponentGlobal_ButtonUploadFileImage({ export function ComponentGlobal_ButtonUploadFileImage({
onSetFile, onSetFile,
onSetImage, onSetImage,
text,
icon,
accept,
}: { }: {
onSetFile: File | any; onSetFile: File | null | any;
onSetImage: any | null; onSetImage?: any | null;
text?: string;
icon?: string | any
accept?: string;
}) { }) {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -24,20 +31,21 @@ export function ComponentGlobal_ButtonUploadFileImage({
new Blob([new Uint8Array(await files.arrayBuffer())]) new Blob([new Uint8Array(await files.arrayBuffer())])
); );
// if (files.size > MAX_SIZE) { if (files.size > 100 * 1024 * 1024) {
// ComponentGlobal_NotifikasiPeringatan(PemberitahuanMaksimalFile); setIsLoading(false);
// return; ComponentGlobal_NotifikasiPeringatan("File terlalu besar");
// } else { return
// } }
onSetFile(files); onSetFile(files);
onSetImage(buffer); onSetImage(buffer);
setIsLoading(false);
} catch (error) { } catch (error) {
clientLogger.error("Upload image error:", error);
} finally {
setIsLoading(false); setIsLoading(false);
clientLogger.error("Upload error:", error);
} }
}} }}
accept="image/png,image/jpeg" accept={accept ? accept : "image/png,image/png,image/jpeg,image/gif"}
> >
{(props) => ( {(props) => (
<Button <Button
@@ -45,12 +53,14 @@ export function ComponentGlobal_ButtonUploadFileImage({
loading={isLoading} loading={isLoading}
loaderPosition="center" loaderPosition="center"
radius={"xl"} radius={"xl"}
leftIcon={<IconCamera />} style={{
bg={MainColor.yellow} backgroundColor: MainColor.yellow,
color="yellow" border: `1px solid ${AccentColor.yellow}`,
c={"black"} }}
leftIcon={icon ? icon : <IconUpload color="black" size={20} />}
c={MainColor.darkblue}
> >
Upload {text ? text : "Upload"}
</Button> </Button>
)} )}
</FileButton> </FileButton>

View File

@@ -1,5 +1,6 @@
import { Center, Grid, Group, Paper, Stack, Text, Title } from "@mantine/core"; import { Center, Grid, Group, Paper, Stack, Text, Title } from "@mantine/core";
import { AccentColor, MainColor } from "../color/color_pallet"; import { AccentColor, MainColor } from "../color/color_pallet";
import { IconInfoCircle } from "@tabler/icons-react";
export default function ComponentGlobal_BoxInformation({ export default function ComponentGlobal_BoxInformation({
informasi, informasi,
@@ -36,18 +37,24 @@ export default function ComponentGlobal_BoxInformation({
</Text> </Text>
</Stack> </Stack>
) : ( ) : (
<Group> <Grid>
<Text fz={fonsize ? fonsize : 12} c={"red"} fw={"bold"}> <Grid.Col span={1}>
*{" "} <IconInfoCircle color={MainColor.white} />
<Text span inherit c={MainColor.white} fw={"normal"}> </Grid.Col>
<Grid.Col span={10}>
<Text
fz={fonsize ? fonsize : 12}
span
inherit
c={MainColor.white}
fw={"normal"}
>
{informasi} {informasi}
</Text> </Text>
</Text> </Grid.Col>
</Group> </Grid>
)} )}
</Paper> </Paper>
</> </>
); );
} }

View File

@@ -1,6 +1,6 @@
import { clientLogger } from "@/util/clientLogger"; import { clientLogger } from "@/util/clientLogger";
export async function funGlobal_DeleteFileById({ export async function funDeteleteFileById({
fileId, fileId,
dirId, dirId,
}: { }: {
@@ -8,9 +8,23 @@ export async function funGlobal_DeleteFileById({
dirId?: string; dirId?: string;
}) { }) {
try { try {
const tokenResponse = await fetch("/api/get-cookie");
if (!tokenResponse.ok) {
return { success: false, message: "Token not found" };
}
const { token } = await tokenResponse.json();
if (!token) {
return { success: false, message: "Token not found" };
}
const res = await fetch("/api/image/delete", { const res = await fetch("/api/image/delete", {
method: "DELETE", method: "DELETE",
body: JSON.stringify({ fileId, dirId }), body: JSON.stringify({ fileId, dirId }),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}); });
const data = await res.json(); const data = await res.json();

View File

@@ -1,7 +1,7 @@
import { funGlobal_DeleteFileById } from "./delete/fun_delete_file_by_id"; import { funDeteleteFileById } from "./delete/fun_delete_file_by_id";
import { funGlobal_UploadToStorage } from "./upload/fun_upload_to_storage"; import { funUploadFileToStorage } from "./upload/fun_upload_to_storage";
import { funValidasiUploadCreatedFile } from "./upload/fun_validasi_upload_created_file"; import { funValidasiUploadCreatedFile } from "./upload/fun_validasi_upload_created_file";
export { funGlobal_UploadToStorage }; export { funUploadFileToStorage as funGlobal_UploadToStorage };
export { funGlobal_DeleteFileById }; export { funDeteleteFileById as funGlobal_DeleteFileById };
export { funValidasiUploadCreatedFile }; export { funValidasiUploadCreatedFile };

View File

@@ -1,55 +1,40 @@
import { TokenStorage } from "@/app/lib/token"; export async function funUploadFileToStorage({
export async function funGlobal_UploadToStorage({
file, file,
dirId, dirId,
}: { }: {
file: File; file: File;
dirId: string; dirId: string;
}) { }) {
const Env_WS_APIKEY = TokenStorage.value; try {
const tokenResponse = await fetch("/api/get-cookie");
if (!tokenResponse.ok) {
throw new Error("Failed to get token");
}
const { token } = await tokenResponse.json();
const allowedMimeTypes = [ if (!token) {
"image/heif", // Format HEIF standar return { success: false, message: "Token not found" };
"image/heic", // Format HEIF untuk container HEIC }
"image/heif-sequence", // Untuk sequence/animasi HEIF
"image/heic-sequence", // Untuk sequence/animasi HEIC
"image/png",
"image/jpeg",
"image/gif",
"text/csv",
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"text/plain",
];
// if (!allowedMimeTypes.includes(file.type)) console.log("File tidak sesuai"); const formData = new FormData();
if (!allowedMimeTypes.includes(file.type)) { formData.append("file", file);
console.error("File tidak sesuai"); formData.append("dirId", dirId);
return { success: false, message: "File type not allowed" };
}
if (file.size > 100 * 1024 * 1024) { const upload = await fetch("/api/image/upload", {
console.error("File terlalu besar"); method: "POST",
return { success: false, message: "File size exceeds limit" }; body: formData,
} headers: {
const formData = new FormData(); Authorization: `Bearer ${token}`,
formData.append("file", file); },
formData.append("dirId", dirId); });
const upload = await fetch("/api/image/upload", { const res = await upload.json();
method: "POST",
body: formData,
});
const res = await upload.json(); return upload.ok
? { success: true, data: res.data, message: res.message }
if (upload.ok) { : { success: false, data: {}, message: res.message };
return { success: true, data: res.data, message: res.message }; } catch (error) {
} else { console.log(error);
return { success: false, data: {}, message: res.message }; return { success: false, message: "An unexpected error occurred" };
} }
} }

View File

@@ -2,8 +2,8 @@ import { clientLogger } from "@/util/clientLogger";
import { MAX_SIZE } from "../../lib"; import { MAX_SIZE } from "../../lib";
import { PemberitahuanMaksimalFile } from "../../lib/max_size"; import { PemberitahuanMaksimalFile } from "../../lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "../../notif_global"; import { ComponentGlobal_NotifikasiPeringatan } from "../../notif_global";
import { funGlobal_DeleteFileById } from "../delete/fun_delete_file_by_id"; import { funDeteleteFileById } from "../delete/fun_delete_file_by_id";
import { funGlobal_UploadToStorage } from "./fun_upload_to_storage"; import { funUploadFileToStorage } from "./fun_upload_to_storage";
export async function funValidasiUploadCreatedFile({ export async function funValidasiUploadCreatedFile({
files, files,
@@ -31,7 +31,7 @@ export async function funValidasiUploadCreatedFile({
} }
if (fileId != "") { if (fileId != "") {
const deleteFotoProfile = await funGlobal_DeleteFileById({ const deleteFotoProfile = await funDeteleteFileById({
fileId: fileId, fileId: fileId,
dirId: dirId, dirId: dirId,
}); });
@@ -49,7 +49,7 @@ export async function funValidasiUploadCreatedFile({
onSetFileId(""); onSetFileId("");
onSetImageBuffer(null); onSetImageBuffer(null);
const uploadPhoto = await funGlobal_UploadToStorage({ const uploadPhoto = await funUploadFileToStorage({
file: files, file: files,
dirId: dirId, dirId: dirId,
}); });
@@ -73,7 +73,7 @@ export async function funValidasiUploadCreatedFile({
} }
} }
} else { } else {
const uploadPhoto = await funGlobal_UploadToStorage({ const uploadPhoto = await funUploadFileToStorage({
file: files, file: files,
dirId: dirId, dirId: dirId,
}); });

View File

@@ -1,16 +0,0 @@
export const apiDeleteImageById = async ({
fileId,
dirId,
}: {
fileId: string;
dirId?: string;
}) => {
const response = await fetch(`/api/image/delete`, {
method: "DELETE",
body: JSON.stringify({ fileId, dirId }),
});
console.log("delete api =>", await response.json());
return await response.json().catch(() => null);
};

View File

@@ -65,6 +65,7 @@ export function Investasi_ComponentButtonCreateNewInvestasi({
dirId: DIRECTORY_ID.investasi_prospektus, dirId: DIRECTORY_ID.investasi_prospektus,
}); });
if (!uploadFilePdf.success) { if (!uploadFilePdf.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload file pdf"); ComponentGlobal_NotifikasiPeringatan("Gagal upload file pdf");
return; return;
} }
@@ -104,17 +105,16 @@ export function Investasi_ComponentButtonCreateNewInvestasi({
router.push(NEW_RouterInvestasi.portofolio({ id: "2" })); router.push(NEW_RouterInvestasi.portofolio({ id: "2" }));
setActiveTab("Review"); setActiveTab("Review");
setHotMenu(1); setHotMenu(1);
setIsLoading(true);
ComponentGlobal_NotifikasiBerhasil(res.message); ComponentGlobal_NotifikasiBerhasil(res.message);
} }
} else { } else {
setIsLoading(false);
ComponentGlobal_NotifikasiGagal(res.message); ComponentGlobal_NotifikasiGagal(res.message);
} }
} catch (error) { } catch (error) {
clientLogger.error("Error create new investasi", error);
} finally {
setIsLoading(false); setIsLoading(false);
} clientLogger.error("Error create new investasi", error);
}
} }
return ( return (

View File

@@ -6,11 +6,15 @@ import {
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { DIRECTORY_ID } from "@/app/lib"; import { DIRECTORY_ID } from "@/app/lib";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun"; import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import _ from "lodash"; import _ from "lodash";
import { investasi_funUpdateInvestasi } from "../../_fun"; import { investasi_funUpdateInvestasi } from "../../_fun";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { clientLogger } from "@/util/clientLogger";
export function Investasi_ComponentButtonUpdateDataInvestasi({ export function Investasi_ComponentButtonUpdateDataInvestasi({
data, data,
@@ -37,11 +41,21 @@ export function Investasi_ComponentButtonUpdateDataInvestasi({
file: file as any, file: file as any,
dirId: DIRECTORY_ID.investasi_image, dirId: DIRECTORY_ID.investasi_image,
}); });
if (!uploadImage.success) { if (!uploadImage.success) {
setIsLoading(false); setIsLoading(false);
return ComponentGlobal_NotifikasiPeringatan("Gagal upload file gambar"); return ComponentGlobal_NotifikasiPeringatan("Gagal upload file gambar");
} }
const deleteFile = await funGlobal_DeleteFileById({
fileId: data.imageId,
});
if (!deleteFile.success) {
setIsLoading(false);
clientLogger.error("Error delete file:", deleteFile.message);
}
const updtWithImage = await investasi_funUpdateInvestasi({ const updtWithImage = await investasi_funUpdateInvestasi({
data: data, data: data,
imageId: uploadImage.data.id, imageId: uploadImage.data.id,

View File

@@ -17,7 +17,7 @@ import {
Text, Text,
} from "@mantine/core"; } from "@mantine/core";
import { IconDots, IconEdit, IconTrash } from "@tabler/icons-react"; import { IconDots, IconEdit, IconTrash } from "@tabler/icons-react";
import { useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface"; import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface";
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader"; import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
@@ -30,6 +30,8 @@ import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { apiGetDokumenInvestasiById } from "../../_lib/api_interface";
import { clientLogger } from "@/util/clientLogger";
export function Investasi_ComponentCardRekapDocument({ export function Investasi_ComponentCardRekapDocument({
data, data,
@@ -38,6 +40,9 @@ export function Investasi_ComponentCardRekapDocument({
data: MODEL_INVESTASI_DOKUMEN; data: MODEL_INVESTASI_DOKUMEN;
onSetData: (val: any) => any[]; onSetData: (val: any) => any[];
}) { }) {
const params = useParams<{ id: string }>();
const investasiId = params.id;
const router = useRouter(); const router = useRouter();
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const [isLoadingEdit, setIsLoadingEdit] = useState(false); const [isLoadingEdit, setIsLoadingEdit] = useState(false);
@@ -63,18 +68,22 @@ export function Investasi_ComponentCardRekapDocument({
if (deleteFromDB.status !== 200) { if (deleteFromDB.status !== 200) {
ComponentGlobal_NotifikasiPeringatan(deleteFromDB.message); ComponentGlobal_NotifikasiPeringatan(deleteFromDB.message);
return;
} }
ComponentGlobal_NotifikasiBerhasil(deleteFromDB.message); ComponentGlobal_NotifikasiBerhasil(deleteFromDB.message);
setOpenModal(false); setOpenModal(false);
const loadData = await investasi_funGetAllDocumentById({ const respone = await apiGetDokumenInvestasiById({
investasiId: data.investasiId, id: investasiId,
page: 1, kategori: "get-all",
page: "1",
}); });
onSetData(loadData); if (respone.success) {
onSetData(respone.data);
}
} catch (error) { } catch (error) {
console.log(error); clientLogger.error("Error hapus dokumen", error);
} finally { } finally {
setIsLoadingDelete(false); setIsLoadingDelete(false);
} }

View File

@@ -0,0 +1,46 @@
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import { Box, Center, Stack } from "@mantine/core";
export { Investasi_SkeletonEditProspektus, Investasi_SkeletonListDokumen };
function Investasi_SkeletonEditProspektus() {
return (
<>
<Stack>
<CustomSkeleton h={70} radius={"md"} />
<CustomSkeleton h={70} radius={"md"} />
<Center>
<CustomSkeleton h={40} w={100} radius={"xl"} />
</Center>
<Box
style={{
display: "flex",
justifyContent: "center",
}}
>
<Box
style={{
transition: "all 0.3s ease",
position: "absolute",
bottom: 20,
width: "90%",
}}
>
<CustomSkeleton h={40} width={"100%"} radius={"xl"} />
</Box>
</Box>
</Stack>
</>
);
}
function Investasi_SkeletonListDokumen() {
return (
<>
<Stack>
<CustomSkeleton h={70} radius={"md"} />
<CustomSkeleton h={70} radius={"md"} />
</Stack>
</>
);
}

View File

@@ -1,13 +1,17 @@
"use server" "use server";
import { prisma } from "@/app/lib" import { prisma } from "@/app/lib";
export async function investasi_funGetOneDocumentById({ documentId }: { documentId: string }) { export async function investasi_funGetOneDocumentById({
const data = await prisma.dokumenInvestasi.findFirst({ documentId,
where: { }: {
id: documentId documentId: string;
} }) {
}) const data = await prisma.dokumenInvestasi.findFirst({
where: {
id: documentId,
},
});
return data return data;
} }

View File

@@ -1,3 +1,19 @@
import { data } from "autoprefixer";
export const apiGetOneInvestasiById = async ({ id }: { id: string }) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/new/investasi/${id}`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
};
export const apiGetMasterInvestasi = async (path?: string) => { export const apiGetMasterInvestasi = async (path?: string) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json()); const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null); if (!token) return await token.json().catch(() => null);
@@ -14,21 +30,6 @@ export const apiGetMasterInvestasi = async (path?: string) => {
return await response.json().catch(() => null); return await response.json().catch(() => null);
}; };
export const apiGetOneInvestasiById = async (path: string) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/new/investasi/${path}`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
};
export const apiGetAllInvestasi = async (path?: string) => { export const apiGetAllInvestasi = async (path?: string) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json()); const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null); if (!token) return await token.json().catch(() => null);
@@ -62,3 +63,55 @@ export const apiGetAllSahamSaya = async (path?: string) => {
); );
return await response.json().catch(() => null); return await response.json().catch(() => null);
}; };
export const apiGetDokumenInvestasiById = async ({
id,
kategori,
page,
}: {
id: string;
kategori?: undefined | "get-all";
page?: string;
}) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(
`/api/new/investasi/dokumen/${id}${kategori ? `?kategori=${kategori}&page=${page}` : ""}`,
{
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
}
);
return await response.json().catch(() => null);
};
export const apiGetBeritaInvestasiById = async ({
id,
kategori,
page,
}: {
id: string;
kategori?: undefined | "get-all";
page?: string;
}) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const onCategory = kategori ? `?kategori=${kategori}&page=${page}` : "";
const response = await fetch(`/api/new/investasi/berita/${id}${onCategory}`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
};

View File

@@ -6,17 +6,13 @@ import {
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { Investasi_ViewCreateBerita } from "../../_view"; import { Investasi_ViewCreateBerita } from "../../_view";
export function Investasi_UiCreateBerita({ export function Investasi_UiCreateBerita() {
investasiId,
}: {
investasiId: string;
}) {
return ( return (
<> <>
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Tambah Berita" />} header={<UIGlobal_LayoutHeaderTamplate title="Tambah Berita" />}
> >
<Investasi_ViewCreateBerita investasiId={investasiId} /> <Investasi_ViewCreateBerita />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
</> </>
); );

View File

@@ -3,13 +3,13 @@
import { UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutTamplate } from "@/app_modules/_global/ui" import { UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutTamplate } from "@/app_modules/_global/ui"
import { Investasi_ViewCreateDocument } from "../../_view"; import { Investasi_ViewCreateDocument } from "../../_view";
export function Investasi_UiCreateDocument({ investasiId }: { investasiId : string}) { export function Investasi_UiCreateDocument() {
return ( return (
<> <>
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Tambah Dokumen" />} header={<UIGlobal_LayoutHeaderTamplate title="Tambah Dokumen" />}
> >
<Investasi_ViewCreateDocument investasiId={investasiId}/> <Investasi_ViewCreateDocument />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
</> </>
); );

View File

@@ -10,40 +10,82 @@ import {
UIGlobal_DrawerCustom, UIGlobal_DrawerCustom,
UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutHeaderTamplate,
UIGlobal_LayoutTamplate, UIGlobal_LayoutTamplate,
UIGlobal_Modal UIGlobal_Modal,
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { ActionIcon, Button, Center, Stack, Text } from "@mantine/core"; import { ActionIcon, Button, Center, Stack, Text } from "@mantine/core";
import { IconDotsVertical, IconTrash } from "@tabler/icons-react"; import { IconDotsVertical, IconTrash } from "@tabler/icons-react";
import { useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { investasi_funDeleteBerita } from "../../_fun"; import { investasi_funDeleteBerita } from "../../_fun";
import { Investasi_ViewDetailBerita } from "../../_view"; import { Investasi_ViewDetailBerita } from "../../_view";
import { DIRECTORY_ID } from "@/app/lib";
import { clientLogger } from "@/util/clientLogger";
import { useShallowEffect } from "@mantine/hooks";
import { apiGetBeritaInvestasiById } from "../../_lib/api_interface";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
export function Investasi_UiDetailBerita({
userLoginId,
}: {
userLoginId: string;
}) {
const params = useParams<{ id: string }>();
const id = params.id;
export function Investasi_UiDetailBerita({ dataBerita }: { dataBerita: any }) {
const router = useRouter(); const router = useRouter();
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const [openModal, setOpenModal] = useState(false); const [openModal, setOpenModal] = useState(false);
const [data, setData] = useState(dataBerita); const [data, setData] = useState<any | null>(null);
const [isLoading, setLoading] = useState(false);
async function onDelete() { useShallowEffect(() => {
const del = await investasi_funDeleteBerita({ onLoadData();
beritaId: dataBerita.id, }, []);
});
if (del.status === 200) { async function onLoadData() {
const deleteImage = await funGlobal_DeleteFileById({ try {
fileId: data.imageId, const respone = await apiGetBeritaInvestasiById({
id: id,
}); });
if (!deleteImage.success) { if (respone) {
ComponentGlobal_NotifikasiPeringatan("Gagal hapus gambar "); setData(respone.data);
} }
} catch (error) {
clientLogger.error("Error get detail berita", error);
}
}
ComponentGlobal_NotifikasiBerhasil(del.message); async function onDelete() {
setOpenModal(false); try {
router.back(); setLoading(true);
} else { const del = await investasi_funDeleteBerita({
ComponentGlobal_NotifikasiGagal(del.message); beritaId: id,
});
if (del.status === 200) {
if (data.imageId != null) {
const deleteImage = await funGlobal_DeleteFileById({
fileId: data.imageId,
dirId: DIRECTORY_ID.investasi_berita,
});
if (!deleteImage.success) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal hapus gambar ");
}
}
router.back();
ComponentGlobal_NotifikasiBerhasil(del.message);
setOpenModal(false);
} else {
setLoading(false);
ComponentGlobal_NotifikasiGagal(del.message);
}
} catch (error) {
setLoading(false);
clientLogger.error("Error delete berita", error);
} }
} }
@@ -54,17 +96,21 @@ export function Investasi_UiDetailBerita({ dataBerita }: { dataBerita: any }) {
<UIGlobal_LayoutHeaderTamplate <UIGlobal_LayoutHeaderTamplate
title="Detail Berita" title="Detail Berita"
customButtonRight={ customButtonRight={
<ActionIcon data && userLoginId === data.investasi.authorId ? (
variant="transparent" <ActionIcon
onClick={() => setOpenDrawer(true)} variant="transparent"
> onClick={() => setOpenDrawer(true)}
<IconDotsVertical color="white" /> >
</ActionIcon> <IconDotsVertical color="white" />
</ActionIcon>
) : (
""
)
} }
/> />
} }
> >
<Investasi_ViewDetailBerita dataBerita={data} /> <Investasi_ViewDetailBerita />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
<UIGlobal_DrawerCustom <UIGlobal_DrawerCustom
@@ -100,6 +146,8 @@ export function Investasi_UiDetailBerita({ dataBerita }: { dataBerita: any }) {
} }
buttonKanan={ buttonKanan={
<Button <Button
loaderPosition="center"
loading={isLoading}
radius="xl" radius="xl"
color="red" color="red"
onClick={() => { onClick={() => {

View File

@@ -6,16 +6,12 @@ import {
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { Investasi_ViewDaftarBerita } from "../../_view"; import { Investasi_ViewDaftarBerita } from "../../_view";
export function Investasi_UiDaftarBerita({ export function Investasi_UiDaftarBerita() {
dataBerita,
}: {
dataBerita: any[];
}) {
return ( return (
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Daftar Berita" />} header={<UIGlobal_LayoutHeaderTamplate title="Daftar Berita" />}
> >
<Investasi_ViewDaftarBerita dataBerita={dataBerita} /> <Investasi_ViewDaftarBerita />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
); );
} }

View File

@@ -6,22 +6,13 @@ import {
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { Investasi_ViewDaftarDokumen } from "../../_view"; import { Investasi_ViewDaftarDokumen } from "../../_view";
export function Investasi_UiDaftarDokmen({ export function Investasi_UiDaftarDokmen() {
dataDokumen,
investasiId,
}: {
dataDokumen: any[];
investasiId: string
}) {
return ( return (
<> <>
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Daftar Dokumen" />} header={<UIGlobal_LayoutHeaderTamplate title="Daftar Dokumen" />}
> >
<Investasi_ViewDaftarDokumen <Investasi_ViewDaftarDokumen />
dataDokumen={dataDokumen}
investasiId={investasiId}
/>
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
</> </>
); );

View File

@@ -1,63 +1,93 @@
"use client"; "use client";
import { NEW_RouterInvestasi } from "@/app/lib/router_hipmi/router_investasi"; import { NEW_RouterInvestasi } from "@/app/lib/router_hipmi/router_investasi";
import { MainColor } from "@/app_modules/_global/color";
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import { import {
UIGlobal_Drawer,
UIGlobal_DrawerCustom, UIGlobal_DrawerCustom,
UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutHeaderTamplate,
UIGlobal_LayoutTamplate, UIGlobal_LayoutTamplate,
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { ActionIcon, Box, SimpleGrid, Stack, Text } from "@mantine/core"; import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import { clientLogger } from "@/util/clientLogger";
import { ActionIcon, SimpleGrid, Stack, Text } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { import {
IconCategoryPlus, IconCategoryPlus,
IconDotsVertical, IconDotsVertical,
IconEdit, IconEdit,
IconFilePencil, IconFilePencil,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import { useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { apiGetOneInvestasiById } from "../../_lib/api_interface";
import { MODEL_INVESTASI } from "../../_lib/interface"; import { MODEL_INVESTASI } from "../../_lib/interface";
import { import {
Investasi_ViewDetailDraft, Investasi_ViewDetailDraft,
Investasi_ViewDetailReject, Investasi_ViewDetailReject,
Investasi_ViewDetailReview, Investasi_ViewDetailReview,
} from "../../_view"; } from "../../_view";
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import { MainColor } from "@/app_modules/_global/color";
export function Investasi_UiDetailPortofolio({ export function Investasi_UiDetailPortofolio() {
dataInvestasi, const params = useParams<{ id: string }>();
userLoginId, const investasiId = params.id;
}: {
dataInvestasi: MODEL_INVESTASI;
userLoginId: string;
}) {
const router = useRouter(); const router = useRouter();
const [isLoading, setLoading] = useState(false); const [isLoading, setLoading] = useState(false);
const [pageId, setPageId] = useState(""); const [pageId, setPageId] = useState("");
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const [data, setData] = useState<any>(dataInvestasi); const [data, setData] = useState<MODEL_INVESTASI | null>(null);
const listPage = [ const listPage = [
{ {
id: "1", id: "1",
name: "Edit Investasi", name: "Edit Investasi",
icon: <IconEdit />, icon: <IconEdit />,
path: NEW_RouterInvestasi.edit_investasi({ id: data.id }), path: NEW_RouterInvestasi.edit_investasi({ id: investasiId }),
}, },
{ {
id: "2", id: "2",
name: "Edit Prospektus", name: "Edit Prospektus",
icon: <IconFilePencil />, icon: <IconFilePencil />,
path: NEW_RouterInvestasi.edit_prospektus({ id: data.id }), path: NEW_RouterInvestasi.edit_prospektus({ id: investasiId }),
}, },
{ {
id: "3", id: "3",
name: "Tambah & Edit Dokumen", name: "Tambah & Edit Dokumen",
icon: <IconCategoryPlus />, icon: <IconCategoryPlus />,
path: NEW_RouterInvestasi.rekap_dokumen({ id: data.id }), path: NEW_RouterInvestasi.rekap_dokumen({ id: investasiId }),
}, },
]; ];
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetOneInvestasiById({
id: investasiId,
});
if (respone.success) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get detail investasi:", error);
}
}
if (data === null) {
return (
<>
<UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title={`Detail`} />}
>
<CustomSkeleton height={"80vh"} />
</UIGlobal_LayoutTamplate>
</>
);
}
if (data.masterStatusInvestasiId == "3") if (data.masterStatusInvestasiId == "3")
return ( return (
<> <>
@@ -76,15 +106,9 @@ export function Investasi_UiDetailPortofolio({
/> />
} }
> >
<Investasi_ViewDetailDraft dataInvestasi={dataInvestasi} /> <Investasi_ViewDetailDraft dataInvestasi={data} />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
{/* <UIGlobal_Drawer
opened={openDrawer}
close={() => setOpenDrawer(false)}
component={listPage}
/> */}
<UIGlobal_DrawerCustom <UIGlobal_DrawerCustom
opened={openDrawer} opened={openDrawer}
close={() => setOpenDrawer(false)} close={() => setOpenDrawer(false)}
@@ -98,9 +122,7 @@ export function Investasi_UiDetailPortofolio({
onClick={() => { onClick={() => {
setPageId(e?.id); setPageId(e?.id);
setLoading(true); setLoading(true);
if (e.id === "1") {
setData({});
}
router.push(e?.path, { scroll: false }); router.push(e?.path, { scroll: false });
}} }}
> >
@@ -125,16 +147,16 @@ export function Investasi_UiDetailPortofolio({
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={ header={
<UIGlobal_LayoutHeaderTamplate <UIGlobal_LayoutHeaderTamplate
title={`Detail ${dataInvestasi.MasterStatusInvestasi.name}`} title={`Detail ${data.MasterStatusInvestasi.name}`}
/> />
} }
> >
{dataInvestasi.masterStatusInvestasiId === "2" && ( {data.masterStatusInvestasiId === "2" && (
<Investasi_ViewDetailReview dataInvestasi={dataInvestasi} /> <Investasi_ViewDetailReview dataInvestasi={data} />
)} )}
{dataInvestasi.masterStatusInvestasiId === "4" && ( {data.masterStatusInvestasiId === "4" && (
<Investasi_ViewDetailReject dataInvestasi={dataInvestasi} /> <Investasi_ViewDetailReject dataInvestasi={data} />
)} )}
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
); );

View File

@@ -1,5 +1,6 @@
"use client"; "use client";
import { NEW_RouterInvestasi } from "@/app/lib/router_hipmi/router_investasi";
import { import {
UIGlobal_Drawer, UIGlobal_Drawer,
UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutHeaderTamplate,
@@ -7,19 +8,13 @@ import {
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { ActionIcon } from "@mantine/core"; import { ActionIcon } from "@mantine/core";
import { IconCirclePlus, IconDotsVertical } from "@tabler/icons-react"; import { IconCirclePlus, IconDotsVertical } from "@tabler/icons-react";
import { useRouter } from "next/navigation"; import { useParams } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Investasi_ViewRekapBerita } from "../../_view"; import { Investasi_ViewRekapBerita } from "../../_view";
import { NEW_RouterInvestasi } from "@/app/lib/router_hipmi/router_investasi";
export function Investasi_UiRekapBerita({ export function Investasi_UiRekapBerita() {
investasiId, const params = useParams<{ id: string }>();
dataBerita, const investasiId = params.id;
}: {
investasiId: string;
dataBerita: any[]
}) {
const router = useRouter();
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const listPage = [ const listPage = [
@@ -32,32 +27,32 @@ export function Investasi_UiRekapBerita({
]; ];
return ( return (
<UIGlobal_LayoutTamplate <>
header={ <UIGlobal_LayoutTamplate
<UIGlobal_LayoutHeaderTamplate header={
title="Rekap Berita" <UIGlobal_LayoutHeaderTamplate
customButtonRight={ title="Rekap Berita"
<ActionIcon customButtonRight={
variant="transparent" <ActionIcon
onClick={() => { variant="transparent"
setOpenDrawer(true); onClick={() => {
}} setOpenDrawer(true);
> }}
<IconDotsVertical color="white" /> >
</ActionIcon> <IconDotsVertical color="white" />
} </ActionIcon>
/> }
} />
> }
>
<Investasi_ViewRekapBerita />
<Investasi_ViewRekapBerita dataBerita={dataBerita} /> </UIGlobal_LayoutTamplate>
<UIGlobal_Drawer <UIGlobal_Drawer
opened={openDrawer} opened={openDrawer}
close={() => setOpenDrawer(false)} close={() => setOpenDrawer(false)}
component={listPage} component={listPage}
/> />
</UIGlobal_LayoutTamplate> </>
); );
} }

View File

@@ -10,16 +10,13 @@ import { ActionIcon } from "@mantine/core";
import { IconCirclePlus, IconDotsVertical } from "@tabler/icons-react"; import { IconCirclePlus, IconDotsVertical } from "@tabler/icons-react";
import { useState } from "react"; import { useState } from "react";
import { Investasi_ViewRekapDokumen } from "../../_view"; import { Investasi_ViewRekapDokumen } from "../../_view";
import { useParams } from "next/navigation";
export function Investasi_UiRekapDokumen() {
const params = useParams<{ id: string }>();
const investasiId = params.id;
export function Investasi_UiRekapDokumen({
investasiId,
dataDokumen,
}: {
investasiId: string;
dataDokumen: any[]
}) {
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const listPage = [ const listPage = [
{ {
id: "1", id: "1",
@@ -47,8 +44,6 @@ export function Investasi_UiRekapDokumen({
} }
> >
<Investasi_ViewRekapDokumen <Investasi_ViewRekapDokumen
dataDokumen={dataDokumen}
investasiId={investasiId}
/> />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>

View File

@@ -6,13 +6,13 @@ import {
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { Investasi_ViewEditDokumen } from "../../_view"; import { Investasi_ViewEditDokumen } from "../../_view";
export function Investasi_UiEditDokumen({ dataDokumen }: { dataDokumen: any }) { export function Investasi_UiEditDokumen() {
return ( return (
<> <>
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Edit Dokumen" />} header={<UIGlobal_LayoutHeaderTamplate title="Edit Dokumen" />}
> >
<Investasi_ViewEditDokumen dataDokumen={dataDokumen} /> <Investasi_ViewEditDokumen />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
</> </>
); );

View File

@@ -1,6 +1,7 @@
"use client"; "use client";
import { UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutTamplate, } from "@/app_modules/_global/ui"; import { UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutTamplate, } from "@/app_modules/_global/ui";
import { Investasi_ViewEditInvestasiNew } from "../../_view/edit/vew_edit_investasi_new"; import { Investasi_ViewEditInvestasiNew } from "../../_view/edit/view_edit_investasi_new";
export function Investasi_UiEditInvestasiNew() { export function Investasi_UiEditInvestasiNew() {
return ( return (

View File

@@ -6,17 +6,13 @@ import {
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { Investasi_ViewEditProspektus } from "../../_view"; import { Investasi_ViewEditProspektus } from "../../_view";
export function Investasi_UiEditProspektus({ export function Investasi_UiEditProspektus() {
investasiId,
}: {
investasiId: string;
}) {
return ( return (
<> <>
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Edit Prospektus" />} header={<UIGlobal_LayoutHeaderTamplate title="Edit Prospektus" />}
> >
<Investasi_ViewEditProspektus investasiId={investasiId} /> <Investasi_ViewEditProspektus />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
</> </>
); );

View File

@@ -1,39 +1,37 @@
import { AccentColor, MainColor } from "@/app_modules/_global/color";
import {
ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage,
ComponentGlobal_InputCountDown,
} from "@/app_modules/_global/component";
import {
ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global";
import {
AspectRatio,
Button,
Center,
FileButton,
Image,
Stack,
Text,
TextInput,
Textarea,
} from "@mantine/core";
import { IconCamera, IconUpload } from "@tabler/icons-react";
import { DIRECTORY_ID } from "@/app/lib"; import { DIRECTORY_ID } from "@/app/lib";
import { MainColor } from "@/app_modules/_global/color";
import {
ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_InputCountDown,
} from "@/app_modules/_global/component";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun"; import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import {
ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global";
import { clientLogger } from "@/util/clientLogger";
import {
AspectRatio,
Button,
Center,
Image,
Stack,
TextInput,
Textarea,
} from "@mantine/core";
import { Prisma } from "@prisma/client"; import { Prisma } from "@prisma/client";
import { useRouter } from "next/navigation"; import { IconPhoto } from "@tabler/icons-react";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { investasi_funCreateBerita } from "../../_fun"; import { investasi_funCreateBerita } from "../../_fun";
export function Investasi_ViewCreateBerita({ export function Investasi_ViewCreateBerita() {
investasiId, const params = useParams<{ id: string }>();
}: { const investasiId = params.id;
investasiId: string;
}) {
const router = useRouter(); const router = useRouter();
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>(); const [img, setImg] = useState<any | null>();
@@ -48,9 +46,6 @@ export function Investasi_ViewCreateBerita({
}); });
async function onCreate() { async function onCreate() {
if (data.data.title == "" || data.data.deskripsi == "")
return ComponentGlobal_NotifikasiPeringatan("Lengkapi data");
try { try {
setIsLoading(true); setIsLoading(true);
if (file != null) { if (file != null) {
@@ -59,32 +54,39 @@ export function Investasi_ViewCreateBerita({
dirId: DIRECTORY_ID.investasi_berita, dirId: DIRECTORY_ID.investasi_berita,
}); });
if (!uploadFile.success) if (!uploadFile.success) {
return ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar"); ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const createWithFile = await investasi_funCreateBerita({ const createWithFile = await investasi_funCreateBerita({
data: data.data as any, data: data.data as any,
fileId: uploadFile.data.id, fileId: uploadFile.data.id,
}); });
createWithFile.status === 201 if (createWithFile.status === 201) {
? (ComponentGlobal_NotifikasiBerhasil(createWithFile.message), ComponentGlobal_NotifikasiBerhasil(createWithFile.message);
router.back()) router.back();
: ComponentGlobal_NotifikasiGagal(createWithFile.message); } else {
setIsLoading(false);
ComponentGlobal_NotifikasiGagal(createWithFile.message);
}
} else { } else {
const createNoFile = await investasi_funCreateBerita({ const createNoFile = await investasi_funCreateBerita({
data: data.data as any, data: data.data as any,
}); });
createNoFile.status === 201 if (createNoFile.status === 201) {
? (ComponentGlobal_NotifikasiBerhasil(createNoFile.message), ComponentGlobal_NotifikasiBerhasil(createNoFile.message);
router.back()) router.back();
: ComponentGlobal_NotifikasiGagal(createNoFile.message); } else {
setIsLoading(false);
ComponentGlobal_NotifikasiGagal(createNoFile.message);
}
} }
} catch (error) { } catch (error) {
console.log(error);
} finally {
setIsLoading(false); setIsLoading(false);
clientLogger.error("Error create news", error);
} }
} }
@@ -106,43 +108,16 @@ export function Investasi_ViewCreateBerita({
</AspectRatio> </AspectRatio>
) : ( ) : (
<Stack justify="center" align="center" h={"100%"}> <Stack justify="center" align="center" h={"100%"}>
<IconUpload color="white" /> <IconPhoto size={100} />
<Text fz={10} fs={"italic"} c={"white"} fw={"bold"}>
Upload Gambar
</Text>
</Stack> </Stack>
)} )}
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFile}
try { onSetImage={setImg}
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())])
);
setImg(buffer);
setFile(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
w={100}
style={{
backgroundColor: MainColor.yellow,
border: `1px solid ${AccentColor.yellow}`,
}}
>
<IconCamera color="black" />
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>
@@ -187,6 +162,10 @@ export function Investasi_ViewCreateBerita({
</Stack> </Stack>
<Button <Button
disabled={data.data.title === "" || data.data.deskripsi === ""}
style={{
transition: "all 0.5s",
}}
loaderPosition="center" loaderPosition="center"
loading={isLoading} loading={isLoading}
my={"md"} my={"md"}

View File

@@ -1,51 +1,53 @@
import { DIRECTORY_ID } from "@/app/lib";
import { MainColor } from "@/app_modules/_global/color"; import { MainColor } from "@/app_modules/_global/color";
import { import {
ComponentGlobal_BoxInformation, ComponentGlobal_BoxInformation,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import {
Stack,
Grid,
Center,
Group,
FileButton,
Button,
Text,
TextInput,
} from "@mantine/core";
import { IconCircleCheck, IconCamera } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { investasi_funCreateDocument } from "../../_fun";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun"; import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import { DIRECTORY_ID } from "@/app/lib";
import { import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { clientLogger } from "@/util/clientLogger";
import {
Box,
Button,
Center,
Grid,
Stack,
Text,
TextInput,
} from "@mantine/core";
import { IconCircleCheck, IconFileTypePdf } from "@tabler/icons-react";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { investasi_funCreateDocument } from "../../_fun";
export function Investasi_ViewCreateDocument() {
const params = useParams<{ id: string }>();
const investasiId = params.id;
export function Investasi_ViewCreateDocument({
investasiId,
}: {
investasiId: string;
}) {
const router = useRouter(); const router = useRouter();
const [filePdf, setFilePdf] = useState<File | null>(null); const [filePdf, setFilePdf] = useState<File | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [title, setTitle] = useState(""); const [title, setTitle] = useState("");
async function onCreate() { async function onCreate() {
setIsLoading(true);
const uploadFileDokumen = await funGlobal_UploadToStorage({
file: filePdf as any,
dirId: DIRECTORY_ID.investasi_dokumen,
});
if (!uploadFileDokumen.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload file pdf");
}
try { try {
setIsLoading(true);
const uploadFileDokumen = await funGlobal_UploadToStorage({
file: filePdf as any,
dirId: DIRECTORY_ID.investasi_dokumen,
});
if (!uploadFileDokumen.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload file pdf");
return;
}
const create = await investasi_funCreateDocument({ const create = await investasi_funCreateDocument({
data: { data: {
investasiId: investasiId, investasiId: investasiId,
@@ -54,15 +56,17 @@ export function Investasi_ViewCreateDocument({
}, },
}); });
if (create.status !== 201) if (create.status !== 201) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan(create.message); ComponentGlobal_NotifikasiPeringatan(create.message);
return;
}
router.back();
ComponentGlobal_NotifikasiBerhasil(create.message); ComponentGlobal_NotifikasiBerhasil(create.message);
router.back();
} catch (error) { } catch (error) {
console.log(error);
} finally {
setIsLoading(false); setIsLoading(false);
clientLogger.error("Error create document", error);
} }
} }
@@ -73,6 +77,7 @@ export function Investasi_ViewCreateDocument({
<Stack> <Stack>
<TextInput <TextInput
withAsterisk
label="Judul Dokumen" label="Judul Dokumen"
placeholder="Masukan judul dokumen" placeholder="Masukan judul dokumen"
styles={{ styles={{
@@ -84,9 +89,9 @@ export function Investasi_ViewCreateDocument({
/> />
<ComponentGlobal_CardStyles marginBottom={"0px"}> <ComponentGlobal_CardStyles marginBottom={"0px"}>
{!filePdf ? ( {!filePdf ? (
<Text lineClamp={1} align="center" c={"gray"}> <Stack justify="center" align="center" h={"100%"}>
Upload Dokumen <IconFileTypePdf size={40} color="gray" />
</Text> </Stack>
) : ( ) : (
<Grid align="center"> <Grid align="center">
<Grid.Col span={2}></Grid.Col> <Grid.Col span={2}></Grid.Col>
@@ -104,55 +109,43 @@ export function Investasi_ViewCreateDocument({
)} )}
</ComponentGlobal_CardStyles> </ComponentGlobal_CardStyles>
<Group position="center"> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
accept={"application/pdf"} onSetFile={setFilePdf}
onChange={async (files: any) => { accept="application/pdf"
try { text="Upload Dokumen"
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())]) </Center>
);
setFilePdf(files);
} catch (error) {
console.log(error);
}
}}
>
{(props) => (
<Button
leftIcon={<IconCamera />}
{...props}
radius={"xl"}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload Dokumen
</Button>
)}
</FileButton>
</Group>
</Stack> </Stack>
<Button <Box
loaderPosition="center"
loading={isLoading}
disabled={filePdf === null || title === ""}
mt={50}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
style={{ style={{
transition: "0.5s", display: "flex",
}} justifyContent: "center",
onClick={() => {
onCreate();
}} }}
> >
Simpan <Button
</Button> loaderPosition="center"
loading={isLoading}
disabled={filePdf === null || title === ""}
mt={50}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
style={{
transition: "0.5s",
position: "absolute",
bottom: 20,
width: "90%",
}}
onClick={() => {
onCreate();
}}
>
Simpan
</Button>
</Box>
</Stack> </Stack>
</> </>
); );

View File

@@ -3,29 +3,55 @@ import {
ComponentGlobal_LoadImageLandscape, ComponentGlobal_LoadImageLandscape,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { Stack, Text, Title } from "@mantine/core"; import { Stack, Text, Title } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { Prisma } from "@prisma/client"; import { Prisma } from "@prisma/client";
import { useParams } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { apiGetBeritaInvestasiById } from "../../_lib/api_interface";
import { clientLogger } from "@/util/clientLogger";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
export function Investasi_ViewDetailBerita({ type MODEL_DATA = Prisma.BeritaInvestasiGetPayload<{}>;
dataBerita,
}: { export function Investasi_ViewDetailBerita() {
dataBerita: any; const params = useParams<{ id: string }>();
}) { const id = params.id;
const [data, setData] =
useState<Prisma.BeritaInvestasiGetPayload<{}>>(dataBerita); const [data, setData] = useState<MODEL_DATA | null>(null);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetBeritaInvestasiById({
id: id,
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get detail berita", error);
}
}
if (!data) {
return <CustomSkeleton height={300} width={"100%"} />;
}
return ( return (
<> <>
<ComponentGlobal_CardStyles> <ComponentGlobal_CardStyles>
<Stack> <Stack>
{data.imageId == null ? ( {data.imagesId && (
"" <ComponentGlobal_LoadImageLandscape
) : ( fileId={data.imageId as string}
<ComponentGlobal_LoadImageLandscape fileId={data.imageId} /> />
)} )}
<Title order={4} align="center"> <Title order={4} align="center">
{" "}
{data.title} {data.title}
</Title> </Title>

View File

@@ -3,43 +3,104 @@ import {
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
ComponentGlobal_CardLoadingOverlay, ComponentGlobal_CardLoadingOverlay,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { Box, Title } from "@mantine/core"; import { clientLogger } from "@/util/clientLogger";
import { useRouter } from "next/navigation"; import { Box, Center, Title } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Investasi_SkeletonListDokumen } from "../../_component/skeleton_view";
import { apiGetBeritaInvestasiById } from "../../_lib/api_interface";
import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import { ScrollOnly } from "next-scroll-loader";
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import _ from "lodash";
export function Investasi_ViewDaftarBerita() {
const params = useParams<{ id: string }>();
const investasiId = params.id;
export function Investasi_ViewDaftarBerita({
dataBerita,
}: {
dataBerita: any[];
}) {
const router = useRouter(); const router = useRouter();
const [data, setData] = useState(dataBerita); const [data, setData] = useState<any[] | null>(null);
const [activePage, setActivePage] = useState(1);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [dataId, setDataId] = useState(""); const [dataId, setDataId] = useState("");
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetBeritaInvestasiById({
id: investasiId,
kategori: "get-all",
page: `${activePage}`,
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get daftar berita", error);
}
}
if (data === null) {
return <Investasi_SkeletonListDokumen />;
}
return ( return (
<> <>
<Box> {_.isEmpty(data) ? (
{data.map((e, i) => ( <ComponentGlobal_IsEmptyData />
<ComponentGlobal_CardStyles ) : (
key={i} <Box>
onClickHandler={() => { <ScrollOnly
router.push(NEW_RouterInvestasi.berita({ id: e.id }), { height="90vh"
scroll: false, renderLoading={() => (
}); <Center>
setVisible(true); <ComponentGlobal_Loader size={25} />
setDataId(e.id); </Center>
)}
data={data}
setData={setData as any}
moreData={async () => {
try {
const respone = await apiGetBeritaInvestasiById({
id: investasiId,
kategori: "get-all",
page: `${activePage + 1}`,
});
if (respone.success) {
setActivePage((val) => val + 1);
return respone.data;
}
} catch (error) {
clientLogger.error("Error load data dokumen:", error);
}
}} }}
> >
<Title order={6} lineClamp={1}> {(item) => (
{e.title} <ComponentGlobal_CardStyles
</Title> onClickHandler={() => {
{visible && dataId === e.id && ( router.push(NEW_RouterInvestasi.berita({ id: item.id }), {
<ComponentGlobal_CardLoadingOverlay /> scroll: false,
});
setVisible(true);
}}
>
<Title order={6} lineClamp={1}>
{item.title}
</Title>
{visible && <ComponentGlobal_CardLoadingOverlay />}
</ComponentGlobal_CardStyles>
)} )}
</ComponentGlobal_CardStyles> </ScrollOnly>
))} </Box>
</Box> )}
</> </>
); );
} }

View File

@@ -7,17 +7,43 @@ import { useState } from "react";
import { Investasi_ComponentCardDaftarDocument } from "../../_component"; import { Investasi_ComponentCardDaftarDocument } from "../../_component";
import { investasi_funGetAllDocumentById } from "../../_fun"; import { investasi_funGetAllDocumentById } from "../../_fun";
import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface"; import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface";
import { useParams } from "next/navigation";
import { Investasi_SkeletonListDokumen } from "../../_component/skeleton_view";
import { clientLogger } from "@/util/clientLogger";
import { apiGetDokumenInvestasiById } from "../../_lib/api_interface";
import { useShallowEffect } from "@mantine/hooks";
export function Investasi_ViewDaftarDokumen({ export function Investasi_ViewDaftarDokumen() {
dataDokumen, const params = useParams<{ id: string }>();
investasiId, const investasiId = params.id;
}: {
dataDokumen: any[]; const [data, setData] = useState<MODEL_INVESTASI_DOKUMEN[] | null>(null);
investasiId: string;
}) {
const [data, setData] = useState<MODEL_INVESTASI_DOKUMEN[]>(dataDokumen);
const [activePage, setActivePage] = useState(1); const [activePage, setActivePage] = useState(1);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetDokumenInvestasiById({
id: investasiId,
kategori: "get-all",
page: `${activePage}`,
});
if (respone.success) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get data dokumen", error);
}
}
if (data === null) {
return <Investasi_SkeletonListDokumen />;
}
return ( return (
<> <>
<Stack> <Stack>
@@ -34,16 +60,23 @@ export function Investasi_ViewDaftarDokumen({
</Center> </Center>
)} )}
data={data} data={data}
setData={setData} setData={setData as any}
moreData={async () => { moreData={async () => {
const loadData = await investasi_funGetAllDocumentById({ try {
investasiId: investasiId, const respone = await apiGetDokumenInvestasiById({
page: activePage + 1, id: investasiId,
}); kategori: "get-all",
page: `${activePage + 1}`,
});
setActivePage((val) => val + 1); if (respone.success) {
setActivePage((val) => val + 1);
return loadData; return respone.data;
}
} catch (error) {
clientLogger.error("Error load data dokumen:", error);
}
}} }}
> >
{(item) => ( {(item) => (

View File

@@ -1,45 +1,108 @@
"use client";
import { NEW_RouterInvestasi } from "@/app/lib/router_hipmi/router_investasi"; import { NEW_RouterInvestasi } from "@/app/lib/router_hipmi/router_investasi";
import { import {
ComponentGlobal_CardLoadingOverlay, ComponentGlobal_CardLoadingOverlay,
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { Box, Group, Title } from "@mantine/core"; import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import { useRouter } from "next/navigation"; import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import { clientLogger } from "@/util/clientLogger";
import { Box, Center, Title } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { ScrollOnly } from "next-scroll-loader";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Investasi_SkeletonListDokumen } from "../../_component/skeleton_view";
import { apiGetBeritaInvestasiById } from "../../_lib/api_interface";
export function Investasi_ViewRekapBerita() {
const params = useParams<{ id: string }>();
const investasiId = params.id;
export function Investasi_ViewRekapBerita({
dataBerita,
}: {
dataBerita: any[];
}) {
const router = useRouter(); const router = useRouter();
const [data, setData] = useState(dataBerita); const [data, setData] = useState<any[] | null>(null);
const [activePage, setActivePage] = useState(1);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [dataId, setDataId] = useState("");
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetBeritaInvestasiById({
id: investasiId,
kategori: "get-all",
page: `${activePage}`,
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get data berita", error);
}
}
if (data === null) {
return <Investasi_SkeletonListDokumen />;
}
return ( return (
<> <>
<Box> {_.isEmpty(data) ? (
{data.map((e, i) => ( <ComponentGlobal_IsEmptyData />
<ComponentGlobal_CardStyles ) : (
key={i} <Box>
onClickHandler={() => { <ScrollOnly
router.push(NEW_RouterInvestasi.berita({ id: e.id }), { height="90vh"
scroll: false, renderLoading={() => (
}); <Center>
setVisible(true); <ComponentGlobal_Loader size={25} />
setDataId(e.id); </Center>
)}
data={data}
setData={setData as any}
moreData={async () => {
try {
const respone = await apiGetBeritaInvestasiById({
id: investasiId,
kategori: "get-all",
page: `${activePage + 1}`,
});
if (respone.success) {
setActivePage((val) => val + 1);
return respone.data;
}
} catch (error) {
clientLogger.error("Error load data dokumen:", error);
}
}} }}
> >
<Title order={6} lineClamp={1}> {(item) => (
{e.title} <ComponentGlobal_CardStyles
</Title> onClickHandler={() => {
{visible && dataId === e.id && ( router.push(NEW_RouterInvestasi.berita({ id: item.id }), {
<ComponentGlobal_CardLoadingOverlay /> scroll: false,
});
setVisible(true);
}}
>
<Title order={6} lineClamp={1}>
{item.title}
</Title>
{visible && (
<ComponentGlobal_CardLoadingOverlay />
)}
</ComponentGlobal_CardStyles>
)} )}
</ComponentGlobal_CardStyles> </ScrollOnly>
))} </Box>
</Box> )}
</> </>
); );
} }

View File

@@ -8,17 +8,41 @@ import { Investasi_ComponentCardRekapDocument } from "../../_component";
import { investasi_funGetAllDocumentById } from "../../_fun"; import { investasi_funGetAllDocumentById } from "../../_fun";
import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface"; import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import { useParams } from "next/navigation";
import { apiGetDokumenInvestasiById } from "../../_lib/api_interface";
import { Investasi_SkeletonListDokumen } from "../../_component/skeleton_view";
import { clientLogger } from "@/util/clientLogger";
export function Investasi_ViewRekapDokumen({ export function Investasi_ViewRekapDokumen() {
dataDokumen, const params = useParams<{ id: string }>();
investasiId, const investasiId = params.id;
}: {
dataDokumen: any[]; const [data, setData] = useState<MODEL_INVESTASI_DOKUMEN[] | null>(null);
investasiId: string;
}) {
const [data, setData] = useState<MODEL_INVESTASI_DOKUMEN[]>(dataDokumen);
const [activePage, setActivePage] = useState(1); const [activePage, setActivePage] = useState(1);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetDokumenInvestasiById({
id: investasiId,
kategori: "get-all",
page: `${activePage}`,
});
if (respone.success) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get data dokumen", error);
}
}
if (data === null) {
return <Investasi_SkeletonListDokumen />;
}
return ( return (
<> <>
@@ -34,16 +58,23 @@ export function Investasi_ViewRekapDokumen({
</Center> </Center>
)} )}
data={data} data={data}
setData={setData} setData={setData as any}
moreData={async () => { moreData={async () => {
const loadData = await investasi_funGetAllDocumentById({ try {
investasiId: investasiId, const respone = await apiGetDokumenInvestasiById({
page: activePage + 1, id: investasiId,
}); kategori: "get-all",
page: `${activePage + 1}`,
});
setActivePage((val) => val + 1); if (respone.success) {
setActivePage((val) => val + 1);
return loadData; return respone.data;
}
} catch (error) {
clientLogger.error("Error load data dokumen:", error);
}
}} }}
> >
{(item) => ( {(item) => (

View File

@@ -1,420 +0,0 @@
import { MainColor } from "@/app_modules/_global/color";
import { ComponentGlobal_BoxInformation, ComponentGlobal_BoxUploadImage, ComponentGlobal_LoadImage, } from "@/app_modules/_global/component";
import { AspectRatio, Box, Button, FileButton, Group, Image, Select, Stack, Text, TextInput, } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { IconCamera } from "@tabler/icons-react";
import _ from "lodash";
import { useState } from "react";
import { Investasi_ComponentButtonUpdateDataInvestasi } from "../../_component";
import { apiGetMasterInvestasi, apiGetOneInvestasiById } from "../../_lib/api_interface";
import { IDataInvestasi } from "../../_lib/type_investasi";
import { useParams } from "next/navigation";
import SkeletonEditInvestasi from "./skeleton_edit_investasi";
export function Investasi_ViewEditInvestasiNew() {
const param = useParams<{ id: string }>()
const [loading, setLoading] = useState(true)
const [loadingMasterInvestor, setLoadingMasterInvestor] = useState(true)
const [loadingMasterPeriodeDeviden, setLoadingMasterPeriodeDeviden] = useState(true)
const [loadingMasterPembagianDeviden, setLoadingMasterPembagianDeviden] = useState(true)
const [periodeDeviden, setPeriodeDeviden] = useState<any[]>([]);
const [pembagianDeviden, setPembagianDeviden] = useState<any[]>([]);
const [pencarianInvestor, setPencarianInvestor] = useState<any[]>([]);
const [data, setData] = useState<IDataInvestasi>();
const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>();
const [target, setTarget] = useState("");
const [harga, setHarga] = useState("");
const [totalLembar, setTotalLembar] = useState<any>("");
async function onGetOneInvestasiById() {
try {
setLoading(true)
const response = await apiGetOneInvestasiById(param.id)
if (response.success) {
setData(response.data)
setTotalLembar(response.data.totalLembar)
}
} catch (error) {
console.error(error)
} finally {
setLoading(false)
}
}
async function onGetMasterInvestor() {
try {
setLoadingMasterInvestor(true)
const response = await apiGetMasterInvestasi("?cat=pencarian-investor")
if (response.success) {
setPencarianInvestor(response.data)
}
} catch (error) {
console.log(error)
} finally {
setLoadingMasterInvestor(false)
}
}
async function onGetMasterPeriodeDeviden() {
try {
setLoadingMasterPeriodeDeviden(true)
const response = await apiGetMasterInvestasi("?cat=periode-deviden")
if (response.success) {
setPeriodeDeviden(response.data)
}
} catch (error) {
console.log(error)
} finally {
setLoadingMasterPeriodeDeviden(false)
}
}
async function onGetMasterPembagianDeviden() {
try {
setLoadingMasterPembagianDeviden(true)
const response = await apiGetMasterInvestasi("?cat=pembagian-deviden")
if (response.success) {
setPembagianDeviden(response.data)
}
} catch (error) {
console.log(error)
} finally {
setLoadingMasterPembagianDeviden(false)
}
}
useShallowEffect(() => {
onGetOneInvestasiById()
onGetMasterInvestor()
onGetMasterPeriodeDeviden()
onGetMasterPembagianDeviden()
}, [])
async function onTotalLembar({ target, harga, }: { target?: number | any; harga?: number | any; }) {
if (target !== 0 && harga !== 0) {
const hasil: any = target / harga;
const result = _.floor(hasil === Infinity ? 0 : hasil);
setTotalLembar(result.toString());
}
}
return (
<>
<Stack px={"sm"}>
{
loading ?
<SkeletonEditInvestasi />
:
<>
<Stack spacing={0}>
<Box mb={"sm"}>
<ComponentGlobal_BoxInformation informasi="Gambar investasi bisa berupa ilustrasi, poster atau foto terkait investasi" />
</Box>
<ComponentGlobal_BoxUploadImage>
{img ? (
<AspectRatio ratio={1 / 1} mt={5} maw={300} mx={"auto"}>
<Image style={{ maxHeight: 250 }} alt="Avatar" src={img} />
</AspectRatio>
) : (
<ComponentGlobal_LoadImage maw={300} fileId={String(data?.imageId)} />
)}
</ComponentGlobal_BoxUploadImage>
{/* Upload Foto */}
<Group position="center">
<FileButton
onChange={async (files: any) => {
try {
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
setImg(buffer);
setFile(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
leftIcon={<IconCamera color="black" />}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload Gambar
</Button>
)}
</FileButton>
</Group>
</Stack>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
}
}}
withAsterisk
label="Judul Investasi"
placeholder="Judul investasi"
maxLength={100}
value={data?.title}
onChange={(val) => {
setData({
...data as any,
title: val.target.value,
});
}}
/>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
}
}}
icon={<Text fw={"bold"}>Rp.</Text>}
min={0}
withAsterisk
label="Dana Dibutuhkan"
placeholder="0"
value={target ? target : data?.targetDana}
onChange={(val) => {
const match = val.currentTarget.value
.replace(/\./g, "")
.match(/^[0-9]+$/);
if (val.currentTarget.value === "") return setTarget(0 + "");
if (!match?.[0]) return null;
const nilai = val.currentTarget.value.replace(/\./g, "");
const targetNilai = Intl.NumberFormat("id-ID").format(+nilai);
onTotalLembar({
target: +nilai,
harga: +Number(data?.hargaLembar),
});
setTarget(targetNilai);
setData({
...data as any,
targetDana: nilai as string,
});
}}
/>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
}
}}
icon={<Text fw={"bold"}>Rp.</Text>}
min={0}
withAsterisk
label="Harga Per Lembar"
placeholder="0"
value={harga ? harga : data?.hargaLembar}
onChange={(val) => {
try {
const match = val.currentTarget.value
.replace(/\./g, "")
.match(/^[0-9]+$/);
if (val.currentTarget.value === "") return setHarga(0 + "");
if (!match?.[0]) return null;
const nilai = val.currentTarget.value.replace(/\./g, "");
const targetNilai = Intl.NumberFormat("id-ID").format(+nilai);
onTotalLembar({
harga: +nilai,
target: +Number(data?.targetDana),
});
setHarga(targetNilai);
setData({
...data as any,
hargaLembar: nilai as string,
});
} catch (error) {
console.log(error);
}
}}
/>
<TextInput
description="*Total lembar dihitung dari, Target Dana / Harga Perlembar"
label="Total Lembar"
value={harga === "0" ? "0" : target === "0" ? "0" : totalLembar}
readOnly
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
}
}}
/>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
}
}}
rightSection={
<Text fw={"bold"} c={"gray"}>
%
</Text>
}
withAsterisk
type="number"
label={"Rasio Keuntungan / ROI %"}
placeholder="Masukan rasio keuntungan"
value={data?.roi}
onChange={(val) => {
setData({
...data as any,
roi: val.target.value,
});
}}
/>
<Select
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
},
dropdown: {
backgroundColor: MainColor.white,
}
}}
withAsterisk
label="Pencarian Investor"
placeholder={loadingMasterInvestor ? "Loading..." : "Pilih batas waktu"}
data={pencarianInvestor.map((e) => ({
value: e.id,
label: e.name + " " + "hari",
}))}
value={data?.masterPencarianInvestorId}
onChange={(val) => {
setData({
...(data as any),
masterPencarianInvestorId: val,
});
}}
/>
<Select
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
},
dropdown: {
backgroundColor: MainColor.white,
}
}}
withAsterisk
label="Periode Deviden"
placeholder={loadingMasterPeriodeDeviden ? "Loading..." : "Pilih batas waktu"}
data={periodeDeviden.map((e) => ({ value: e.id, label: e.name }))}
value={data?.masterPeriodeDevidenId}
onChange={(val) => {
setData({
...(data as any),
masterPeriodeDevidenId: val,
});
}}
/>
<Select
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red
},
dropdown: {
backgroundColor: MainColor.white,
}
}}
withAsterisk
label="Pembagian Deviden"
placeholder={loadingMasterPembagianDeviden ? "Loading..." : "Pilih batas waktu"}
data={pembagianDeviden.map((e) => ({
value: e.id,
label: e.name + " " + "bulan",
}))}
value={data?.masterPembagianDevidenId}
onChange={(val) => {
setData({
...(data as any),
masterPembagianDevidenId: val,
});
}}
/>
<Investasi_ComponentButtonUpdateDataInvestasi
data={data as any}
file={file as any}
totalLembar={totalLembar}
/>
</>
}
</Stack>
</>
);
}

View File

@@ -1,7 +1,8 @@
import { DIRECTORY_ID } from "@/app/lib"; import { DIRECTORY_ID } from "@/app/lib";
import { MainColor } from "@/app_modules/_global/color"; import { MainColor } from "@/app_modules/_global/color";
import { import {
ComponentGlobal_CardStyles ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { import {
funGlobal_DeleteFileById, funGlobal_DeleteFileById,
@@ -11,44 +12,62 @@ import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { clientLogger } from "@/util/clientLogger";
import { import {
Box,
Button, Button,
Center, Center,
FileButton,
Grid, Grid,
Group,
Stack, Stack,
Text, Text,
TextInput, TextInput,
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera, IconCircleCheck } from "@tabler/icons-react"; import { useShallowEffect } from "@mantine/hooks";
import { IconCircleCheck } from "@tabler/icons-react";
import _ from "lodash"; import _ from "lodash";
import { useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Investasi_SkeletonEditProspektus } from "../../_component/skeleton_view";
import { investasi_funUpdateDocument } from "../../_fun"; import { investasi_funUpdateDocument } from "../../_fun";
import { apiGetDokumenInvestasiById } from "../../_lib/api_interface";
import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface"; import { MODEL_INVESTASI_DOKUMEN } from "../../_lib/interface";
export function Investasi_ViewEditDokumen({ export function Investasi_ViewEditDokumen() {
dataDokumen, const params = useParams<{ id: string }>();
}: { const dokumenId = params.id;
dataDokumen: MODEL_INVESTASI_DOKUMEN;
}) {
const router = useRouter(); const router = useRouter();
const [filePdf, setFilePdf] = useState<File | null>(null); const [filePdf, setFilePdf] = useState<File | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState(dataDokumen); const [data, setData] = useState<MODEL_INVESTASI_DOKUMEN | null>(null);
const [title, setTitle] = useState(data.title); // const [title, setTitle] = useState(data.title);
const [loading, setLoading] = useState(true);
useShallowEffect(() => {
onGetDataDokumenById();
}, []);
async function onGetDataDokumenById() {
try {
setLoading(true);
const response = await apiGetDokumenInvestasiById({
id: dokumenId,
});
if (response.success) {
console.log(response.data);
setData(response.data);
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
async function onUpdate() { async function onUpdate() {
try { try {
setIsLoading(true); setIsLoading(true);
if (filePdf) { if (filePdf) {
const delfile = await funGlobal_DeleteFileById({ fileId: data.fileId });
if (!delfile.success) {
ComponentGlobal_NotifikasiPeringatan("Gagal hapus file lama");
}
const uploadFile = await funGlobal_UploadToStorage({ const uploadFile = await funGlobal_UploadToStorage({
file: filePdf, file: filePdf,
dirId: DIRECTORY_ID.investasi_dokumen, dirId: DIRECTORY_ID.investasi_dokumen,
@@ -57,35 +76,52 @@ export function Investasi_ViewEditDokumen({
if (!uploadFile.success) { if (!uploadFile.success) {
setIsLoading(false); setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload file dokumen"); ComponentGlobal_NotifikasiPeringatan("Gagal upload file dokumen");
return;
}
const delfile = await funGlobal_DeleteFileById({
fileId: data?.fileId as any,
dirId: DIRECTORY_ID.investasi_dokumen,
});
if (!delfile.success) {
setIsLoading(false);
clientLogger.error("Gagal hapus file lama", delfile.message);
} }
const updateWithFile = await investasi_funUpdateDocument({ const updateWithFile = await investasi_funUpdateDocument({
data: data, data: data as any,
fileId: uploadFile.data.id, fileId: uploadFile.data.id,
}); });
if (updateWithFile.status !== 200) { if (updateWithFile.status !== 200) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan(updateWithFile.message); ComponentGlobal_NotifikasiPeringatan(updateWithFile.message);
} }
ComponentGlobal_NotifikasiBerhasil(updateWithFile.message); ComponentGlobal_NotifikasiBerhasil(updateWithFile.message);
router.back();
} else { } else {
const updateNoFile = await investasi_funUpdateDocument({ const updateNoFile = await investasi_funUpdateDocument({
data: data, data: data as any,
}); });
if (updateNoFile.status !== 200) { if (updateNoFile.status !== 200) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan(updateNoFile.message); ComponentGlobal_NotifikasiPeringatan(updateNoFile.message);
} }
ComponentGlobal_NotifikasiBerhasil(updateNoFile.message); ComponentGlobal_NotifikasiBerhasil(updateNoFile.message);
} }
} catch (error) { } catch (error) {
console.log(error);
} finally {
router.back();
setIsLoading(false); setIsLoading(false);
clientLogger.error(" Error update dokumen", error);
} }
} }
if (loading) {
return <Investasi_SkeletonEditProspektus />;
}
return ( return (
<> <>
<Stack spacing={"xl"} px={"sm"}> <Stack spacing={"xl"} px={"sm"}>
@@ -95,18 +131,23 @@ export function Investasi_ViewEditDokumen({
<TextInput <TextInput
label="Judul Dokumen" label="Judul Dokumen"
placeholder="Masukan judul dokumen" placeholder="Masukan judul dokumen"
value={data.title} value={data?.title}
styles={{ styles={{
label: { label: {
color: "white", color: "white",
}, },
}} }}
onChange={(val) => setData({ ...data, title: val.target.value })} onChange={(val) =>
setData({
...(data as any),
title: val.target.value,
})
}
/> />
<ComponentGlobal_CardStyles marginBottom={"0px"}> <ComponentGlobal_CardStyles marginBottom={"0px"}>
{!filePdf ? ( {!filePdf ? (
<Text lineClamp={1} align="center" c={"gray"}> <Text lineClamp={1} align="center" c={"gray"}>
Dokumen {_.startCase(title)}.pdf {_.startCase(data?.title)}.pdf
</Text> </Text>
) : ( ) : (
<Grid align="center"> <Grid align="center">
@@ -125,7 +166,15 @@ export function Investasi_ViewEditDokumen({
)} )}
</ComponentGlobal_CardStyles> </ComponentGlobal_CardStyles>
<Group position="center"> <Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={setFilePdf}
accept="application/pdf"
text="Upload dokumen"
/>
</Center>
{/* <Group position="center">
<FileButton <FileButton
accept={"application/pdf"} accept={"application/pdf"}
onChange={async (files: any) => { onChange={async (files: any) => {
@@ -153,27 +202,37 @@ export function Investasi_ViewEditDokumen({
</Button> </Button>
)} )}
</FileButton> </FileButton>
</Group> </Group> */}
</Stack> </Stack>
<Button <Box
loaderPosition="center"
loading={isLoading}
disabled={data.title === ""}
mt={50}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
style={{ style={{
transition: "0.5s", display: "flex",
}} justifyContent: "center",
onClick={() => {
onUpdate();
}} }}
> >
Update <Button
</Button> loaderPosition="center"
loading={isLoading}
disabled={data?.title === ""}
mt={50}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
style={{
transition: "0.5s",
position: "absolute",
bottom: 20,
width: "90%",
}}
onClick={() => {
onUpdate();
}}
>
Update
</Button>
</Box>
</Stack> </Stack>
</> </>
); );

View File

@@ -0,0 +1,465 @@
import { MainColor } from "@/app_modules/_global/color";
import {
ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_LoadImage,
} from "@/app_modules/_global/component";
import {
AspectRatio,
Box,
Button,
Center,
FileButton,
Group,
Image,
Select,
Stack,
Text,
TextInput,
} from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { IconCamera } from "@tabler/icons-react";
import _ from "lodash";
import { useState } from "react";
import { Investasi_ComponentButtonUpdateDataInvestasi } from "../../_component";
import {
apiGetMasterInvestasi,
apiGetOneInvestasiById,
} from "../../_lib/api_interface";
import { IDataInvestasi } from "../../_lib/type_investasi";
import { useParams } from "next/navigation";
import SkeletonEditInvestasi from "./skeleton_edit_investasi";
export function Investasi_ViewEditInvestasiNew() {
const param = useParams<{ id: string }>();
const [loading, setLoading] = useState(true);
const [loadingMasterInvestor, setLoadingMasterInvestor] = useState(true);
const [loadingMasterPeriodeDeviden, setLoadingMasterPeriodeDeviden] =
useState(true);
const [loadingMasterPembagianDeviden, setLoadingMasterPembagianDeviden] =
useState(true);
const [periodeDeviden, setPeriodeDeviden] = useState<any[]>([]);
const [pembagianDeviden, setPembagianDeviden] = useState<any[]>([]);
const [pencarianInvestor, setPencarianInvestor] = useState<any[]>([]);
const [data, setData] = useState<IDataInvestasi>();
const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>();
const [target, setTarget] = useState("");
const [harga, setHarga] = useState("");
const [totalLembar, setTotalLembar] = useState<any>("");
async function onGetOneInvestasiById() {
try {
setLoading(true);
const response = await apiGetOneInvestasiById({
id: param.id,
});
if (response.success) {
setData(response.data);
setTotalLembar(response.data.totalLembar);
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
async function onGetMasterInvestor() {
try {
setLoadingMasterInvestor(true);
const response = await apiGetMasterInvestasi("?cat=pencarian-investor");
if (response.success) {
setPencarianInvestor(response.data);
}
} catch (error) {
console.log(error);
} finally {
setLoadingMasterInvestor(false);
}
}
async function onGetMasterPeriodeDeviden() {
try {
setLoadingMasterPeriodeDeviden(true);
const response = await apiGetMasterInvestasi("?cat=periode-deviden");
if (response.success) {
setPeriodeDeviden(response.data);
}
} catch (error) {
console.log(error);
} finally {
setLoadingMasterPeriodeDeviden(false);
}
}
async function onGetMasterPembagianDeviden() {
try {
setLoadingMasterPembagianDeviden(true);
const response = await apiGetMasterInvestasi("?cat=pembagian-deviden");
if (response.success) {
setPembagianDeviden(response.data);
}
} catch (error) {
console.log(error);
} finally {
setLoadingMasterPembagianDeviden(false);
}
}
useShallowEffect(() => {
onGetOneInvestasiById();
onGetMasterInvestor();
onGetMasterPeriodeDeviden();
onGetMasterPembagianDeviden();
}, []);
async function onTotalLembar({
target,
harga,
}: {
target?: number | any;
harga?: number | any;
}) {
if (target !== 0 && harga !== 0) {
const hasil: any = target / harga;
const result = _.floor(hasil === Infinity ? 0 : hasil);
setTotalLembar(result.toString());
}
}
return (
<>
<Stack px={"sm"}>
{loading ? (
<SkeletonEditInvestasi />
) : (
<>
<Stack spacing={0}>
<Box mb={"sm"}>
<ComponentGlobal_BoxInformation informasi="Gambar investasi bisa berupa ilustrasi, poster atau foto terkait investasi" />
</Box>
<ComponentGlobal_BoxUploadImage>
{img ? (
<AspectRatio ratio={1 / 1} mt={5} maw={300} mx={"auto"}>
<Image style={{ maxHeight: 250 }} alt="Avatar" src={img} />
</AspectRatio>
) : (
<ComponentGlobal_LoadImage
maw={300}
fileId={String(data?.imageId)}
/>
)}
</ComponentGlobal_BoxUploadImage>
{/* Upload Foto */}
<Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={setFile}
onSetImage={setImg}
/>
</Center>
{/* <Group position="center">
<FileButton
onChange={async (files: any) => {
try {
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
setImg(buffer);
setFile(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
leftIcon={<IconCamera color="black" />}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload Gambar
</Button>
)}
</FileButton>
</Group> */}
</Stack>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
}}
withAsterisk
label="Judul Investasi"
placeholder="Judul investasi"
maxLength={100}
value={data?.title}
onChange={(val) => {
setData({
...(data as any),
title: val.target.value,
});
}}
/>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
}}
icon={<Text fw={"bold"}>Rp.</Text>}
min={0}
withAsterisk
label="Dana Dibutuhkan"
placeholder="0"
value={target ? target : data?.targetDana}
onChange={(val) => {
const match = val.currentTarget.value
.replace(/\./g, "")
.match(/^[0-9]+$/);
if (val.currentTarget.value === "") return setTarget(0 + "");
if (!match?.[0]) return null;
const nilai = val.currentTarget.value.replace(/\./g, "");
const targetNilai = Intl.NumberFormat("id-ID").format(+nilai);
onTotalLembar({
target: +nilai,
harga: +Number(data?.hargaLembar),
});
setTarget(targetNilai);
setData({
...(data as any),
targetDana: nilai as string,
});
}}
/>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
}}
icon={<Text fw={"bold"}>Rp.</Text>}
min={0}
withAsterisk
label="Harga Per Lembar"
placeholder="0"
value={harga ? harga : data?.hargaLembar}
onChange={(val) => {
try {
const match = val.currentTarget.value
.replace(/\./g, "")
.match(/^[0-9]+$/);
if (val.currentTarget.value === "") return setHarga(0 + "");
if (!match?.[0]) return null;
const nilai = val.currentTarget.value.replace(/\./g, "");
const targetNilai = Intl.NumberFormat("id-ID").format(+nilai);
onTotalLembar({
harga: +nilai,
target: +Number(data?.targetDana),
});
setHarga(targetNilai);
setData({
...(data as any),
hargaLembar: nilai as string,
});
} catch (error) {
console.log(error);
}
}}
/>
<TextInput
description="*Total lembar dihitung dari, Target Dana / Harga Perlembar"
label="Total Lembar"
value={harga === "0" ? "0" : target === "0" ? "0" : totalLembar}
readOnly
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
}}
/>
<TextInput
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
}}
rightSection={
<Text fw={"bold"} c={"gray"}>
%
</Text>
}
withAsterisk
type="number"
label={"Rasio Keuntungan / ROI %"}
placeholder="Masukan rasio keuntungan"
value={data?.roi}
onChange={(val) => {
setData({
...(data as any),
roi: val.target.value,
});
}}
/>
<Select
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
dropdown: {
backgroundColor: MainColor.white,
},
}}
withAsterisk
label="Pencarian Investor"
placeholder={
loadingMasterInvestor ? "Loading..." : "Pilih batas waktu"
}
data={pencarianInvestor.map((e) => ({
value: e.id,
label: e.name + " " + "hari",
}))}
value={data?.masterPencarianInvestorId}
onChange={(val) => {
setData({
...(data as any),
masterPencarianInvestorId: val,
});
}}
/>
<Select
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
dropdown: {
backgroundColor: MainColor.white,
},
}}
withAsterisk
label="Periode Deviden"
placeholder={
loadingMasterPeriodeDeviden ? "Loading..." : "Pilih batas waktu"
}
data={periodeDeviden.map((e) => ({ value: e.id, label: e.name }))}
value={data?.masterPeriodeDevidenId}
onChange={(val) => {
setData({
...(data as any),
masterPeriodeDevidenId: val,
});
}}
/>
<Select
styles={{
label: {
color: MainColor.white,
},
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
dropdown: {
backgroundColor: MainColor.white,
},
}}
withAsterisk
label="Pembagian Deviden"
placeholder={
loadingMasterPembagianDeviden
? "Loading..."
: "Pilih batas waktu"
}
data={pembagianDeviden.map((e) => ({
value: e.id,
label: e.name + " " + "bulan",
}))}
value={data?.masterPembagianDevidenId}
onChange={(val) => {
setData({
...(data as any),
masterPembagianDevidenId: val,
});
}}
/>
<Investasi_ComponentButtonUpdateDataInvestasi
data={data as any}
file={file as any}
totalLembar={totalLembar}
/>
</>
)}
</Stack>
</>
);
}

View File

@@ -1,82 +1,120 @@
import { MainColor } from "@/app_modules/_global/color"; import { MainColor } from "@/app_modules/_global/color";
import { import {
ComponentGlobal_BoxInformation, ComponentGlobal_BoxInformation,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { import {
Box,
Button, Button,
Center, Center,
FileButton,
Grid, Grid,
Group,
Stack, Stack,
Text Text
} from "@mantine/core"; } from "@mantine/core";
import { import {
IconCamera, IconCircleCheck,
IconCircleCheck IconFileTypePdf
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import { DIRECTORY_ID } from "@/app/lib"; import { DIRECTORY_ID } from "@/app/lib";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun"; import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { useRouter } from "next/navigation"; import { clientLogger } from "@/util/clientLogger";
import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Investasi_SkeletonEditProspektus } from "../../_component/skeleton_view";
import { investasi_funUpdateProspektus } from "../../_fun"; import { investasi_funUpdateProspektus } from "../../_fun";
import { apiGetOneInvestasiById } from "../../_lib/api_interface";
export function Investasi_ViewEditProspektus({ export function Investasi_ViewEditProspektus() {
investasiId, const params = useParams<{ id: string }>();
}: { const investasiId = params.id;
investasiId: string;
}) {
const router = useRouter(); const router = useRouter();
const [filePdf, setFilePdf] = useState<File | null>(null); const [filePdf, setFilePdf] = useState<File | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [fileRemoveId, setFileRemoveId] = useState<string | null>(null);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetOneInvestasiById({
id: investasiId,
});
if (respone.success) {
setFileRemoveId(respone.data.prospektusFileId);
}
} catch (error) {
clientLogger.error("Error get data investasi:", error);
}
}
async function onUpload() { async function onUpload() {
setIsLoading(true);
const uploadFilePdf = await funGlobal_UploadToStorage({
file: filePdf as any,
dirId: DIRECTORY_ID.investasi_prospektus,
});
if (!uploadFilePdf.success) {
setIsLoading(false);
return ComponentGlobal_NotifikasiPeringatan("Gagal upload file pdf");
}
try { try {
setIsLoading(true);
const uploadFilePdf = await funGlobal_UploadToStorage({
file: filePdf as any,
dirId: DIRECTORY_ID.investasi_prospektus,
});
if (!uploadFilePdf.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload file pdf");
return;
}
const deleteFile = await funGlobal_DeleteFileById({
fileId: fileRemoveId as string,
dirId: DIRECTORY_ID.investasi_prospektus,
});
if (!deleteFile.success) {
setIsLoading(false);
clientLogger.error("Error delete file:", deleteFile.message);
}
const updte = await investasi_funUpdateProspektus({ const updte = await investasi_funUpdateProspektus({
fileId: uploadFilePdf.data.id, fileId: uploadFilePdf.data.id,
investasiId: investasiId, investasiId: investasiId,
}); });
if (updte.status !== 200) { if (updte.status !== 200) {
return ComponentGlobal_NotifikasiPeringatan("Gagal update prospektus"); setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal update prospektus");
return;
} }
ComponentGlobal_NotifikasiBerhasil(updte.message);
router.back(); router.back();
return ComponentGlobal_NotifikasiBerhasil(updte.message);
} catch (error) { } catch (error) {
console.log(error);
} finally {
setIsLoading(false); setIsLoading(false);
clientLogger.error("Error update prospektus:", error);
} }
} }
if (fileRemoveId == null) {
return <Investasi_SkeletonEditProspektus />;
}
return ( return (
<> <>
<Stack spacing={"sm"}> <Stack spacing={"sm"}>
<ComponentGlobal_BoxInformation informasi="File prospektus wajib untuk diupload, agar calon investor paham dengan prospek investasi yang akan anda jalankan kedepan !" /> <ComponentGlobal_BoxInformation informasi="File prospektus wajib untuk diupload, agar calon investor paham dengan prospek investasi yang akan anda jalankan kedepan." />
<ComponentGlobal_CardStyles marginBottom={"0px"}> <ComponentGlobal_CardStyles marginBottom={"0px"}>
{!filePdf ? ( {!filePdf ? (
<Text lineClamp={1} align="center" c={"gray"}> <Stack justify="center" align="center" h={"100%"}>
Upload File Prospektus <IconFileTypePdf size={40} color="gray" />
</Text> </Stack>
) : ( ) : (
<Grid align="center"> <Grid align="center">
<Grid.Col span={2}></Grid.Col> <Grid.Col span={2}></Grid.Col>
@@ -94,54 +132,43 @@ export function Investasi_ViewEditProspektus({
)} )}
</ComponentGlobal_CardStyles> </ComponentGlobal_CardStyles>
<Group position="center"> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onSetFile={setFilePdf}
accept={"application/pdf"} accept={"application/pdf"}
onChange={async (files: any) => { text="Upload File"
try { />
const buffer = URL.createObjectURL( </Center>
new Blob([new Uint8Array(await files.arrayBuffer())])
);
setFilePdf(files); <Box
} catch (error) {
console.log(error);
}
}}
>
{(props) => (
<Button
leftIcon={<IconCamera />}
{...props}
radius={"xl"}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload File
</Button>
)}
</FileButton>
</Group>
<Button
loaderPosition="center"
loading={isLoading}
disabled={filePdf === null}
mt={50}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
style={{ style={{
transition: "0.5s", display: "flex",
}} justifyContent: "center",
onClick={() => {
onUpload();
}} }}
> >
Update <Button
</Button> px={"sm"}
loaderPosition="center"
loading={isLoading}
disabled={filePdf === null}
mt={50}
radius={50}
bg={MainColor.yellow}
color="yellow"
c={"black"}
style={{
transition: "all 0.3s ease",
position: "absolute",
bottom: 20,
width: "90%",
}}
onClick={() => {
onUpload();
}}
>
Update
</Button>
</Box>
</Stack> </Stack>
</> </>
); );

View File

@@ -32,6 +32,7 @@ import { IRealtimeData } from "@/app/lib/global_state";
import { notifikasiToAdmin_funCreate } from "@/app_modules/notifikasi/fun"; import { notifikasiToAdmin_funCreate } from "@/app_modules/notifikasi/fun";
import { WibuRealtime } from "wibu-pkg"; import { WibuRealtime } from "wibu-pkg";
import { clientLogger } from "@/util/clientLogger"; import { clientLogger } from "@/util/clientLogger";
import { ComponentGlobal_ButtonUploadFileImage } from "@/app_modules/_global/component";
export function Investasi_ViewInvoice({ export function Investasi_ViewInvoice({
dataInvoice, dataInvoice,
@@ -42,6 +43,7 @@ export function Investasi_ViewInvoice({
const [isLoading, setLoading] = useState(false); const [isLoading, setLoading] = useState(false);
const [data, setData] = useState(dataInvoice); const [data, setData] = useState(dataInvoice);
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>(null);
async function onUpload() { async function onUpload() {
try { try {
@@ -52,6 +54,7 @@ export function Investasi_ViewInvoice({
}); });
if (!uploadFileToStorage.success) { if (!uploadFileToStorage.success) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload bukti transfer"); ComponentGlobal_NotifikasiPeringatan("Gagal upload bukti transfer");
return; return;
} }
@@ -62,6 +65,7 @@ export function Investasi_ViewInvoice({
}); });
if (res.status != 200) { if (res.status != 200) {
setLoading(false);
ComponentGlobal_NotifikasiGagal(res.message); ComponentGlobal_NotifikasiGagal(res.message);
return; return;
} }
@@ -93,9 +97,8 @@ export function Investasi_ViewInvoice({
}); });
} }
} catch (error) { } catch (error) {
clientLogger.error(" Error upload invoice", error);
} finally {
setLoading(false); setLoading(false);
clientLogger.error(" Error upload invoice", error);
} }
} }
@@ -245,29 +248,10 @@ export function Investasi_ViewInvoice({
> >
<Stack spacing={"sm"}> <Stack spacing={"sm"}>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFile}
try { accept="image/png,image/png,image/jpeg,application/pdf"
setFile(files); />
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
leftIcon={<IconCamera />}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload
</Button>
)}
</FileButton>
</Center> </Center>
{file ? ( {file ? (
<Center> <Center>

View File

@@ -3,6 +3,7 @@ import { MainColor } from "@/app_modules/_global/color/color_pallet";
import { import {
ComponentGlobal_BoxInformation, ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage, ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { MAX_SIZE } from "@/app_modules/_global/lib"; import { MAX_SIZE } from "@/app_modules/_global/lib";
@@ -131,7 +132,7 @@ export default function InvestasiCreateNew() {
{/* Upload Image */} {/* Upload Image */}
<Stack spacing={0}> <Stack spacing={0}>
<Box mb={"sm"}> <Box mb={"sm"}>
<ComponentGlobal_BoxInformation informasi="Gambar investasi bisa berupa ilustrasi, poster atau foto terkait investasi" /> <ComponentGlobal_BoxInformation informasi="Gambar investasi bisa berupa ilustrasi, poster atau foto terkait investasi." />
</Box> </Box>
<ComponentGlobal_BoxUploadImage> <ComponentGlobal_BoxUploadImage>
{isLoadingImg ? ( {isLoadingImg ? (
@@ -155,7 +156,13 @@ export default function InvestasiCreateNew() {
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
{/* Upload Foto */} {/* Upload Foto */}
<Group position="center"> <Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={setFileImage}
onSetImage={setImg}
/>
</Center>
{/* <Group position="center">
<FileButton <FileButton
onChange={async (files: any) => { onChange={async (files: any) => {
try { try {
@@ -196,12 +203,12 @@ export default function InvestasiCreateNew() {
</Button> </Button>
)} )}
</FileButton> </FileButton>
</Group> </Group> */}
</Stack> </Stack>
{/* Upload File */} {/* Upload File */}
<Stack spacing={"sm"}> <Stack spacing={"sm"}>
<ComponentGlobal_BoxInformation informasi="File prospektus wajib untuk diupload, agar calon investor paham dengan prospek investasi yang akan anda jalankan kedepan !" /> <ComponentGlobal_BoxInformation informasi="File prospektus wajib untuk diupload, agar calon investor paham dengan prospek investasi yang akan anda jalankan kedepannya." />
<ComponentGlobal_CardStyles marginBottom={"0px"}> <ComponentGlobal_CardStyles marginBottom={"0px"}>
{isLoadingPdf ? ( {isLoadingPdf ? (
<Stack justify="center" align="center" h={"100%"}> <Stack justify="center" align="center" h={"100%"}>
@@ -228,7 +235,16 @@ export default function InvestasiCreateNew() {
)} )}
</ComponentGlobal_CardStyles> </ComponentGlobal_CardStyles>
<Group position="center"> <Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={setFilePdf}
onSetImage={setFPdf}
accept={"application/pdf"}
text="Upload File"
icon={<IconFileTypePdf size={20} />}
/>
</Center>
{/* <Group position="center">
<FileButton <FileButton
accept={"application/pdf"} accept={"application/pdf"}
onChange={async (files: any) => { onChange={async (files: any) => {
@@ -269,7 +285,7 @@ export default function InvestasiCreateNew() {
</Button> </Button>
)} )}
</FileButton> </FileButton>
</Group> </Group> */}
</Stack> </Stack>
<Stack> <Stack>
@@ -283,7 +299,7 @@ export default function InvestasiCreateNew() {
}, },
input: { input: {
backgroundColor: MainColor.white, backgroundColor: MainColor.white,
} },
}} }}
withAsterisk withAsterisk
label="Judul Investasi" label="Judul Investasi"
@@ -307,7 +323,7 @@ export default function InvestasiCreateNew() {
}, },
input: { input: {
backgroundColor: MainColor.white, backgroundColor: MainColor.white,
} },
}} }}
icon={<Text fw={"bold"}>Rp.</Text>} icon={<Text fw={"bold"}>Rp.</Text>}
min={0} min={0}
@@ -350,7 +366,7 @@ export default function InvestasiCreateNew() {
}, },
input: { input: {
backgroundColor: MainColor.white, backgroundColor: MainColor.white,
} },
}} }}
icon={<Text fw={"bold"}>Rp.</Text>} icon={<Text fw={"bold"}>Rp.</Text>}
min={0} min={0}
@@ -403,7 +419,7 @@ export default function InvestasiCreateNew() {
}, },
input: { input: {
backgroundColor: MainColor.white, backgroundColor: MainColor.white,
} },
}} }}
/> />
@@ -417,7 +433,7 @@ export default function InvestasiCreateNew() {
}, },
input: { input: {
backgroundColor: MainColor.white, backgroundColor: MainColor.white,
} },
}} }}
rightSection={ rightSection={
<Text fw={"bold"} c={"gray"}> <Text fw={"bold"} c={"gray"}>

View File

@@ -1,60 +0,0 @@
"use client";
import { RouterInvestasi_OLD } from "@/app/lib/router_hipmi/router_investasi";
import UIGlobal_Drawer from "@/app_modules/_global/ui/ui_drawer";
import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_tamplate";
import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate";
import { ActionIcon } from "@mantine/core";
import { IconDotsVertical, IconFilePlus } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import React from "react";
export default function LayoutEditDokumenInvestasi({
children,
idInves,
}: {
children: React.ReactNode;
idInves: string;
}) {
const router = useRouter();
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
const listPage = [
{
id: "1",
name: "Tambah Dokumen",
icon: <IconFilePlus />,
path: RouterInvestasi_OLD.upload_dokumen + `${idInves}`,
},
];
return (
<>
<UIGlobal_LayoutTamplate
header={
<UIGlobal_LayoutHeaderTamplate
title="Daftar Dokumen"
// iconRight={<IconEdit />}
// routerRight={RouterInvestasi.upload_dokumen + `${idInves}`}
customButtonRight={
<ActionIcon
variant="transparent"
onClick={() => setIsOpenDrawer(true)}
>
<IconDotsVertical color="white" />
</ActionIcon>
}
/>
}
>
{children}
</UIGlobal_LayoutTamplate>
<UIGlobal_Drawer
opened={isOpenDrawer}
close={() => setIsOpenDrawer(false)}
component={listPage}
/>
</>
);
}

View File

@@ -1,87 +0,0 @@
"use client";
import {
AccentColor,
MainColor,
} from "@/app_modules/_global/color/color_pallet";
import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal";
import { ActionIcon, Group, Paper, Text } from "@mantine/core";
import { IconFolderOpen, IconTrash, IconWorldShare } from "@tabler/icons-react";
import _ from "lodash";
import Link from "next/link";
import { useState } from "react";
import funDeleteDokumenInvestasi from "../fun/fun_delete_dokumen";
import funLoadDataInvestasi from "../fun/fun_load_data";
import { MODEL_INVESTASI } from "../_lib/interface";
import { IconFile } from "@tabler/icons-react";
import { IconFileTypePdf } from "@tabler/icons-react";
export default function EditDokumenInvestasi({
dataInvestasi,
}: {
dataInvestasi: MODEL_INVESTASI;
}) {
const [dokumen, setDokumen] = useState(dataInvestasi);
async function onDelete(id: string) {
await funDeleteDokumenInvestasi(id).then(async (res) => {
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message);
const load = await funLoadDataInvestasi(dokumen.id);
setDokumen(load as any);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}
return (
<>
{!_.isEmpty(dokumen.DokumenInvestasi) ? (
dokumen.DokumenInvestasi.map((e) => (
<Paper
key={e.id}
style={{
padding: "15px",
backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px",
color: "white",
marginBottom: "15px",
}}
>
<Group position="apart">
<Text lineClamp={1}>{e.title}</Text>
<Group position="center">
<Link href={`/file/${e.url}`} target="_blank">
<ActionIcon variant="transparent">
<IconFileTypePdf
style={{
color: MainColor.yellow,
}}
/>
</ActionIcon>
</Link>
<ActionIcon
variant="transparent"
onClick={() => {
onDelete(e.id);
}}
>
<IconTrash color="red" />
</ActionIcon>
</Group>
</Group>
</Paper>
))
) : (
<ComponentGlobal_IsEmptyData />
)}
{/* <Divider mt={"lg"} /> */}
</>
);
}

View File

@@ -1,30 +0,0 @@
"use client";
import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_tamplate";
import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate";
import React from "react";
import { MODEL_INVESTASI } from "../_lib/interface";
export default function LayoutEditProspektusInvestasi({
children,
dataInvestasi,
}: {
children: React.ReactNode;
dataInvestasi: MODEL_INVESTASI;
}) {
return (
<>
<UIGlobal_LayoutTamplate
header={
<UIGlobal_LayoutHeaderTamplate
title="Edit Prospektus"
// icon={<IconEdit />}
// route2={RouterInvestasi.upload_prospektus + `${dataInvestasi.id}`}
/>
}
>
{children}
</UIGlobal_LayoutTamplate>
</>
);
}

View File

@@ -1,75 +0,0 @@
"use client";
import {
Paper,
Grid,
Center,
Title,
Divider,
Button,
Text,
Group,
FileButton,
FileInput,
Image,
AspectRatio,
Flex,
Stack,
Box,
} from "@mantine/core";
import { IconChevronRight, IconFileTypePdf } from "@tabler/icons-react";
import Link from "next/link";
import { useState } from "react";
import { MODEL_INVESTASI } from "../_lib/interface";
import { RouterInvestasi_OLD } from "@/app/lib/router_hipmi/router_investasi";
export default function EditProspektusInvestasi({
dataInvestasi,
}: {
dataInvestasi: MODEL_INVESTASI;
}) {
const [prospek, setProspek] = useState<MODEL_INVESTASI>(dataInvestasi);
return (
<>
{/* <pre>{JSON.stringify(prospek, null, 2)}</pre> */}
<Stack>
{prospek.ProspektusInvestasi != null ? (
<Link
href={RouterInvestasi_OLD.api_file_prospektus + `${prospek.ProspektusInvestasi.id}`}
target="_blank"
style={{ textDecorationLine: "none" }}
>
<Paper w={"100%"} bg={"gray"} mb={"md"}>
<Grid
align="center"
justify="center"
h={50}
px={"sm"}
onClick={() => ""}
>
<Grid.Col span={11}>
<Group>
{/* <IconFileTypePdf /> */}
<Text lineClamp={1}>Prospektus_{prospek.title}</Text>
</Group>
</Grid.Col>
<Grid.Col span={1}>
<Center>
<IconChevronRight />
</Center>
</Grid.Col>
</Grid>
</Paper>
</Link>
) : (
<Center>
<Title order={4}>Tidak ada file</Title>
</Center>
)}
{/* <Divider my={"lg"} /> */}
</Stack>
</>
);
}

View File

@@ -7,10 +7,6 @@ import PortofolioInvestasi from "./portofolio/view";
import LayoutPortofolioInvestasi from "./portofolio/layout"; import LayoutPortofolioInvestasi from "./portofolio/layout";
import EditIntroInvestasi from "./edit_intro/view"; import EditIntroInvestasi from "./edit_intro/view";
import LayoutEditIntroInvestasi from "./edit_intro/layout"; import LayoutEditIntroInvestasi from "./edit_intro/layout";
import EditProspektusInvestasi from "./edit_propektus/view";
import LayoutEditProspektusInvestasi from "./edit_propektus/layout";
import EditDokumenInvestasi from "./edit_dokumen/view";
import LayoutEditDokumenInvestasi from "./edit_dokumen/layout";
import EditBeritaInvestasi from "./edit_berita/view"; import EditBeritaInvestasi from "./edit_berita/view";
import LayoutEditBeritaInvestasi from "./edit_berita/layout"; import LayoutEditBeritaInvestasi from "./edit_berita/layout";
import DetailPropektus from "./detail_prospektus/view"; import DetailPropektus from "./detail_prospektus/view";
@@ -58,10 +54,6 @@ export {
LayoutPortofolioInvestasi, LayoutPortofolioInvestasi,
EditIntroInvestasi, EditIntroInvestasi,
LayoutEditIntroInvestasi, LayoutEditIntroInvestasi,
EditProspektusInvestasi,
LayoutEditProspektusInvestasi,
EditDokumenInvestasi,
LayoutEditDokumenInvestasi,
EditBeritaInvestasi, EditBeritaInvestasi,
LayoutEditBeritaInvestasi, LayoutEditBeritaInvestasi,
DetailPropektus, DetailPropektus,

View File

@@ -11,6 +11,7 @@ import {
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { notifikasiToAdmin_funCreate } from "@/app_modules/notifikasi/fun"; import { notifikasiToAdmin_funCreate } from "@/app_modules/notifikasi/fun";
import { clientLogger } from "@/util/clientLogger";
import { Button } from "@mantine/core"; import { Button } from "@mantine/core";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@@ -19,7 +20,6 @@ import { WibuRealtime } from "wibu-pkg";
import { job_funCreateNoFile, job_funCreateWithFile } from "../../fun"; import { job_funCreateNoFile, job_funCreateWithFile } from "../../fun";
import { gs_job_hot_menu } from "../../global_state"; import { gs_job_hot_menu } from "../../global_state";
import { MODEL_JOB } from "../../model/interface"; import { MODEL_JOB } from "../../model/interface";
import { envs } from "@/lib/envs";
function Job_ComponentButtonSaveCreate({ function Job_ComponentButtonSaveCreate({
value, value,
@@ -71,6 +71,8 @@ function Job_ComponentButtonSaveCreate({
ComponentGlobal_NotifikasiBerhasil(createNoFile.message); ComponentGlobal_NotifikasiBerhasil(createNoFile.message);
} }
} else { } else {
setIsLoading(false);
ComponentGlobal_NotifikasiGagal(createNoFile.message); ComponentGlobal_NotifikasiGagal(createNoFile.message);
} }
} else { } else {
@@ -80,6 +82,7 @@ function Job_ComponentButtonSaveCreate({
}); });
if (!uploadFile.success) { if (!uploadFile.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar"); ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return; return;
} }
@@ -120,15 +123,13 @@ function Job_ComponentButtonSaveCreate({
ComponentGlobal_NotifikasiBerhasil(createWithFile.message); ComponentGlobal_NotifikasiBerhasil(createWithFile.message);
} }
} else { } else {
setIsLoading(false);
ComponentGlobal_NotifikasiGagal(createWithFile.message); ComponentGlobal_NotifikasiGagal(createWithFile.message);
} }
} }
} catch (error) { } catch (error) {
console.log(error); setIsLoading(false);
} finally { clientLogger.error("Error create job", error);
if (window.location.pathname !== RouterJob.status({ id: "2" })) {
setIsLoading(false);
}
} }
} }

View File

@@ -17,6 +17,7 @@ import { useState } from "react";
import { job_EditById } from "../../fun/edit/fun_edit_by_id"; import { job_EditById } from "../../fun/edit/fun_edit_by_id";
import { gs_job_hot_menu } from "../../global_state"; import { gs_job_hot_menu } from "../../global_state";
import { MODEL_JOB } from "../../model/interface"; import { MODEL_JOB } from "../../model/interface";
import { clientLogger } from "@/util/clientLogger";
export function Job_ComponentButtonUpdateData({ export function Job_ComponentButtonUpdateData({
value, value,
@@ -32,41 +33,56 @@ export function Job_ComponentButtonUpdateData({
const [opened, { open, close }] = useDisclosure(false); const [opened, { open, close }] = useDisclosure(false);
async function onUpdate() { async function onUpdate() {
if (file === null) { try {
const update = await job_EditById({ setIsLoading(true);
data: value,
});
if (update.status !== 200)
return ComponentGlobal_NotifikasiGagal(update.message);
} else {
const uploadFile = await funGlobal_UploadToStorage({
file: file,
dirId: DIRECTORY_ID.job_image,
});
if (!uploadFile.success) if (file === null) {
return ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar"); const update = await job_EditById({
data: value,
if (value.imageId !== null) {
const delFile = await funGlobal_DeleteFileById({
fileId: value.imageId,
}); });
if (!delFile.success) if (update.status !== 200)
ComponentGlobal_NotifikasiPeringatan("Gagal hapus gambar lama"); return ComponentGlobal_NotifikasiGagal(update.message);
} else {
const uploadFile = await funGlobal_UploadToStorage({
file: file,
dirId: DIRECTORY_ID.job_image,
});
if (!uploadFile.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
if (value.imageId !== null) {
const delFile = await funGlobal_DeleteFileById({
fileId: value.imageId,
});
if (!delFile.success) {
clientLogger.error("Error delete file:", delFile.message);
}
}
const updateWithFile = await job_EditById({
data: value,
fileId: uploadFile.data.id,
});
if (updateWithFile.status !== 200) {
setIsLoading(false);
ComponentGlobal_NotifikasiGagal(updateWithFile.message);
return;
}
} }
const updateWithFile = await job_EditById({ setHotMenu(2);
data: value, ComponentGlobal_NotifikasiBerhasil("Berhasil Update");
fileId: uploadFile.data.id, router.back();
}); } catch (error) {
if (updateWithFile.status !== 200) setIsLoading(false);
return ComponentGlobal_NotifikasiGagal(updateWithFile.message); clientLogger.error("Error update job:", error);
ComponentGlobal_NotifikasiGagal("Gagal update job");
} }
setHotMenu(2);
setIsLoading(true);
router.back();
return ComponentGlobal_NotifikasiBerhasil("Berhasil Update");
} }
return ( return (

View File

@@ -2,15 +2,13 @@
import { import {
AspectRatio, AspectRatio,
Button,
Center, Center,
FileButton,
Image, Image,
Stack, Stack,
Text, Text,
TextInput, TextInput,
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera, IconUpload } from "@tabler/icons-react"; import { IconPhoto } from "@tabler/icons-react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useState } from "react"; import { useState } from "react";
import "react-quill/dist/quill.snow.css"; import "react-quill/dist/quill.snow.css";
@@ -21,22 +19,15 @@ const ReactQuill = dynamic(
{ ssr: false } { ssr: false }
); );
import {
AccentColor,
MainColor,
} from "@/app_modules/_global/color/color_pallet";
import { import {
ComponentGlobal_BoxInformation, ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage, ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
ComponentGlobal_InputCountDown, ComponentGlobal_InputCountDown,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import { Job_ComponentButtonSaveCreate } from "../component"; import { Job_ComponentButtonSaveCreate } from "../component";
import { defaultDeskripsi, defaultSyarat } from "../component/default_value"; import { defaultDeskripsi, defaultSyarat } from "../component/default_value";
import { MAX_SIZE } from "@/app_modules/_global/lib";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
export default function Job_Create() { export default function Job_Create() {
const [value, setValue] = useState({ const [value, setValue] = useState({
@@ -55,7 +46,7 @@ export default function Job_Create() {
<Stack> <Stack>
<ComponentGlobal_BoxInformation informasi="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja. " /> <ComponentGlobal_BoxInformation informasi="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja. " />
<Stack spacing={"xs"}> <Stack spacing={0}>
<ComponentGlobal_BoxUploadImage> <ComponentGlobal_BoxUploadImage>
{img ? ( {img ? (
<AspectRatio ratio={1 / 1} mah={265} mx={"auto"}> <AspectRatio ratio={1 / 1} mah={265} mx={"auto"}>
@@ -68,53 +59,16 @@ export default function Job_Create() {
</AspectRatio> </AspectRatio>
) : ( ) : (
<Stack justify="center" align="center" h={"100%"}> <Stack justify="center" align="center" h={"100%"}>
<IconUpload color="white" /> <IconPhoto size={100} />
<Text fz={10} fs={"italic"} c={"white"} fw={"bold"}>
Upload Gambar
</Text>
</Stack> </Stack>
)} )}
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFile}
try { onSetImage={setImg}
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())])
);
if (files.size > MAX_SIZE) {
ComponentGlobal_NotifikasiPeringatan(
PemberitahuanMaksimalFile
);
setImg(null);
return;
}
setImg(buffer);
setFile(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
w={100}
style={{
backgroundColor: MainColor.yellow,
border: `1px solid ${AccentColor.yellow}`,
}}
>
<IconCamera color="black" />
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>

View File

@@ -2,36 +2,26 @@
import { import {
AspectRatio, AspectRatio,
Button,
Center, Center,
FileButton,
Image, Image,
Stack, Stack,
Text, Text,
TextInput, TextInput,
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera, IconUpload } from "@tabler/icons-react";
import { useState } from "react"; import { useState } from "react";
import { MODEL_JOB } from "../model/interface"; import { MODEL_JOB } from "../model/interface";
import { APIs } from "@/app/lib";
import {
AccentColor,
MainColor,
} from "@/app_modules/_global/color/color_pallet";
import { import {
ComponentGlobal_BoxUploadImage, ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_CardStyles, ComponentGlobal_CardStyles,
ComponentGlobal_LoadImage, ComponentGlobal_LoadImage,
ComponentGlobal_LoadImageCustom,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown"; import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown";
import { IconPhoto } from "@tabler/icons-react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import "react-quill/dist/quill.snow.css"; import "react-quill/dist/quill.snow.css";
import { import { Job_ComponentButtonUpdate } from "../component";
Job_ComponentBoxUploadImage,
Job_ComponentButtonUpdate,
} from "../component";
const ReactQuill = dynamic( const ReactQuill = dynamic(
() => { () => {
return import("react-quill"); return import("react-quill");
@@ -51,7 +41,7 @@ export default function Job_Edit({ dataJob }: { dataJob: MODEL_JOB }) {
return ( return (
<> <>
<Stack> <Stack>
<Stack spacing={"xs"}> <Stack spacing={0}>
<ComponentGlobal_BoxUploadImage> <ComponentGlobal_BoxUploadImage>
{img ? ( {img ? (
<AspectRatio ratio={1 / 1} mt={5} maw={300} mx={"auto"}> <AspectRatio ratio={1 / 1} mt={5} maw={300} mx={"auto"}>
@@ -66,44 +56,16 @@ export default function Job_Edit({ dataJob }: { dataJob: MODEL_JOB }) {
<ComponentGlobal_LoadImage fileId={data.imageId} /> <ComponentGlobal_LoadImage fileId={data.imageId} />
) : ( ) : (
<Stack justify="center" align="center" h={"100%"}> <Stack justify="center" align="center" h={"100%"}>
<IconUpload color="white" /> <IconPhoto size={100} />
<Text fz={10} fs={"italic"} c={"white"} fw={"bold"}>
Upload Gambar
</Text>
</Stack> </Stack>
)} )}
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFile}
try { onSetImage={setImg}
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())])
);
setImg(buffer);
setFile(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
w={100}
style={{
backgroundColor: MainColor.yellow,
border: `1px solid ${AccentColor.yellow}`,
}}
>
<IconCamera color="black" />
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>

View File

@@ -1,22 +1,22 @@
"use client"; "use client";
import { AccentColor, MainColor } from "@/app_modules/_global/color"; import { MainColor } from "@/app_modules/_global/color";
import { import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal, ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { Button } from "@mantine/core"; import { Box, Button } from "@mantine/core";
import { useRouter } from "next/navigation"; import { DIRECTORY_ID } from "@/app/lib";
import { useState } from "react";
import { import {
funGlobal_DeleteFileById, funGlobal_DeleteFileById,
funGlobal_UploadToStorage, funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun"; } from "@/app_modules/_global/fun";
import { DIRECTORY_ID } from "@/app/lib";
import { portofolio_funEditLogoBisnisById } from "../../fun";
import { clientLogger } from "@/util/clientLogger"; import { clientLogger } from "@/util/clientLogger";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { portofolio_funEditLogoBisnisById } from "../../fun";
export function ComponentPortofolio_ButtonEditLogoBisnis({ export function ComponentPortofolio_ButtonEditLogoBisnis({
file, file,
@@ -33,16 +33,6 @@ export function ComponentPortofolio_ButtonEditLogoBisnis({
try { try {
setLoading(true); setLoading(true);
const deleteLogo = await funGlobal_DeleteFileById({
fileId: fileRemoveId,
dirId: DIRECTORY_ID.portofolio_logo,
});
if (!deleteLogo.success) {
setLoading(false);
clientLogger.error("Error delete logo", deleteLogo.message);
}
const uploadFileToStorage = await funGlobal_UploadToStorage({ const uploadFileToStorage = await funGlobal_UploadToStorage({
file: file, file: file,
dirId: DIRECTORY_ID.portofolio_logo, dirId: DIRECTORY_ID.portofolio_logo,
@@ -53,9 +43,21 @@ export function ComponentPortofolio_ButtonEditLogoBisnis({
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar"); ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return; return;
} }
const deleteLogo = await funGlobal_DeleteFileById({
fileId: fileRemoveId,
dirId: DIRECTORY_ID.portofolio_logo,
});
if (!deleteLogo.success) {
setLoading(false);
clientLogger.error("Error delete logo", deleteLogo.message);
}
const logoId = uploadFileToStorage.data.id;
const res = await portofolio_funEditLogoBisnisById({ const res = await portofolio_funEditLogoBisnisById({
portofolioId: portofolioId, portofolioId: portofolioId,
logoId: uploadFileToStorage.data.id, logoId: logoId,
}); });
if (res.status === 200) { if (res.status === 200) {
@@ -73,8 +75,16 @@ export function ComponentPortofolio_ButtonEditLogoBisnis({
return ( return (
<> <>
{file ? ( <Box
p={"xs"}
bg={"red"}
style={{
display: "flex",
justifyContent: "center",
}}
>
<Button <Button
disabled={file === null}
loaderPosition="center" loaderPosition="center"
loading={loading} loading={loading}
radius={"xl"} radius={"xl"}
@@ -83,17 +93,15 @@ export function ComponentPortofolio_ButtonEditLogoBisnis({
color="yellow" color="yellow"
c={"black"} c={"black"}
style={{ style={{
width: "100%",
transition: "0.5s", transition: "0.5s",
border: `1px solid ${AccentColor.yellow}`, position: "absolute",
bottom: 20,
}} }}
> >
Simpan Simpan
</Button> </Button>
) : ( </Box>
<Button disabled radius={"xl"}>
Simpan
</Button>
)}
</> </>
); );
} }

View File

@@ -9,6 +9,9 @@ import { MODEL_PORTOFOLIO_OLD } from "@/app_modules/model_global/portofolio";
import { Button } from "@mantine/core"; import { Button } from "@mantine/core";
import _ from "lodash"; import _ from "lodash";
import { DIRECTORY_ID } from "@/app/lib";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import { clientLogger } from "@/util/clientLogger";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import funCreatePortofolio from "../../fun/fun_create_portofolio"; import funCreatePortofolio from "../../fun/fun_create_portofolio";
@@ -17,12 +20,12 @@ export function Portofolio_ComponentButtonSelanjutnya({
profileId, profileId,
dataPortofolio, dataPortofolio,
dataMedsos, dataMedsos,
imageId, file,
}: { }: {
profileId: string; profileId: string;
dataPortofolio: MODEL_PORTOFOLIO_OLD; dataPortofolio: MODEL_PORTOFOLIO_OLD;
dataMedsos: any; dataMedsos: any;
imageId: string; file: File;
}) { }) {
const router = useRouter(); const router = useRouter();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -48,31 +51,45 @@ export function Portofolio_ComponentButtonSelanjutnya({
try { try {
setLoading(true); setLoading(true);
const uploadFile = await funGlobal_UploadToStorage({
file: file,
dirId: DIRECTORY_ID.portofolio_logo,
});
if (!uploadFile.success) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const fileId = uploadFile.data.id;
const res = await funCreatePortofolio({ const res = await funCreatePortofolio({
profileId: profileId, profileId: profileId,
data: dataPortofolio as any, data: dataPortofolio as any,
medsos: dataMedsos, medsos: dataMedsos,
fileId: imageId, fileId: fileId,
}); });
if (res.status === 201) { if (res.status === 201) {
ComponentGlobal_NotifikasiBerhasil("Berhasil disimpan"); ComponentGlobal_NotifikasiBerhasil("Berhasil disimpan");
router.replace(RouterMap.create + res.id, { scroll: false }); router.replace(RouterMap.create + res.id, { scroll: false });
} else { } else {
setLoading(false);
ComponentGlobal_NotifikasiGagal("Gagal disimpan"); ComponentGlobal_NotifikasiGagal("Gagal disimpan");
} }
} catch (error) { } catch (error) {
console.error(error);
} finally {
setLoading(false); setLoading(false);
clientLogger.error("Error create portofolio", error);
} }
} }
return ( return (
<> <>
<Button <Button
disabled={_.values(dataPortofolio).includes("") || imageId == ""} disabled={_.values(dataPortofolio).includes("") || file === null}
mt={"md"} mt={"md"}
radius={50} radius={50}
loading={loading ? true : false} loading={loading}
loaderPosition="center" loaderPosition="center"
onClick={() => { onClick={() => {
onSubmit(); onSubmit();

View File

@@ -1,9 +1,20 @@
"use client"; "use client";
import { DIRECTORY_ID } from "@/app/lib";
import { MainColor } from "@/app_modules/_global/color/color_pallet"; import { MainColor } from "@/app_modules/_global/color/color_pallet";
import { ComponentGlobal_BoxUploadImage } from "@/app_modules/_global/component"; import {
ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
} from "@/app_modules/_global/component";
import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information"; import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information";
import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown"; import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { MAX_SIZE } from "@/app_modules/_global/lib";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
import { BIDANG_BISNIS_OLD } from "@/app_modules/model_global/portofolio"; import { BIDANG_BISNIS_OLD } from "@/app_modules/model_global/portofolio";
import { import {
AspectRatio, AspectRatio,
@@ -18,20 +29,12 @@ import {
Textarea, Textarea,
Title, Title,
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera } from "@tabler/icons-react"; import { IconCamera, IconPhoto } from "@tabler/icons-react";
import _ from "lodash"; import _ from "lodash";
import { useState } from "react"; import { useState } from "react";
import { Portofolio_ComponentButtonSelanjutnya } from "../component";
import { MAX_SIZE } from "@/app_modules/_global/lib";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { DIRECTORY_ID } from "@/app/lib";
import { PhoneInput } from "react-international-phone"; import { PhoneInput } from "react-international-phone";
import "react-international-phone/style.css"; import "react-international-phone/style.css";
import { Portofolio_ComponentButtonSelanjutnya } from "../component";
export default function CreatePortofolio({ export default function CreatePortofolio({
bidangBisnis, bidangBisnis,
@@ -56,16 +59,15 @@ export default function CreatePortofolio({
tiktok: "", tiktok: "",
}); });
const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>(null); const [img, setImg] = useState<any | null>(null);
const [imageId, setImageId] = useState(""); const [imageId, setImageId] = useState("");
return ( return (
<> <>
{/* {JSON.stringify(profileId)} */}
<Stack px={"sm"} mb={"lg"} spacing={50}> <Stack px={"sm"} mb={"lg"} spacing={50}>
<Stack spacing={"sm"}> <Stack spacing={"sm"}>
<ComponentGlobal_BoxInformation informasi="Lengkapi Data Bisnis" /> <ComponentGlobal_BoxInformation informasi="Lengkapi data bisnis" />
<TextInput <TextInput
styles={{ styles={{
label: { label: {
@@ -101,8 +103,8 @@ export default function CreatePortofolio({
color: MainColor.red, color: MainColor.red,
}, },
dropdown: { dropdown: {
backgroundColor: MainColor.white backgroundColor: MainColor.white,
} },
}} }}
withAsterisk withAsterisk
label="Bidang Bisnis" label="Bidang Bisnis"
@@ -156,7 +158,7 @@ export default function CreatePortofolio({
countrySelectorStyleProps={{ countrySelectorStyleProps={{
buttonStyle: { buttonStyle: {
backgroundColor: MainColor.login, backgroundColor: MainColor.login,
} },
}} }}
inputStyle={{ width: "100%", backgroundColor: MainColor.login }} inputStyle={{ width: "100%", backgroundColor: MainColor.login }}
defaultCountry="id" defaultCountry="id"
@@ -205,7 +207,7 @@ export default function CreatePortofolio({
</Stack> </Stack>
<Stack> <Stack>
<ComponentGlobal_BoxInformation informasi="Upload Logo Bisnis Anda" /> <ComponentGlobal_BoxInformation informasi="Upload logo bisnis anda untuk ditampilkan dalam portofolio " />
<ComponentGlobal_BoxUploadImage> <ComponentGlobal_BoxUploadImage>
{img ? ( {img ? (
<AspectRatio ratio={1 / 1} mah={265} mx={"auto"}> <AspectRatio ratio={1 / 1} mah={265} mx={"auto"}>
@@ -218,17 +220,19 @@ export default function CreatePortofolio({
</AspectRatio> </AspectRatio>
) : ( ) : (
<Stack spacing={5} justify="center" align="center" h={"100%"}> <Stack spacing={5} justify="center" align="center" h={"100%"}>
<Title c={MainColor.white} order={3}> <IconPhoto size={100} />
Upload Logo Bisnis
</Title>
<Text c={MainColor.white} fs={"italic"} fz={10} align="center">
Masukan logo bisnis anda untuk ditampilkan dalam portofolio
</Text>
</Stack> </Stack>
)} )}
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={setFile}
onSetImage={setImg}
/>
</Center>
{/* <Center>
<FileButton <FileButton
onChange={async (files: any | null) => { onChange={async (files: any | null) => {
try { try {
@@ -310,7 +314,7 @@ export default function CreatePortofolio({
</Button> </Button>
)} )}
</FileButton> </FileButton>
</Center> </Center> */}
</Stack> </Stack>
<Stack> <Stack>
@@ -416,7 +420,8 @@ export default function CreatePortofolio({
dataPortofolio={dataPortofolio as any} dataPortofolio={dataPortofolio as any}
dataMedsos={dataMedsos} dataMedsos={dataMedsos}
profileId={profileId} profileId={profileId}
imageId={imageId} //
file={file as File}
/> />
</Stack> </Stack>
</> </>

View File

@@ -1,19 +1,16 @@
"use client"; "use client";
import { APIs } from "@/app/lib";
import { import {
AccentColor, AccentColor
MainColor,
} from "@/app_modules/_global/color/color_pallet"; } from "@/app_modules/_global/color/color_pallet";
import { ComponentGlobal_LoadImage } from "@/app_modules/_global/component"; import {
import { Button, Center, FileButton, Image, Paper, Stack } from "@mantine/core"; ComponentGlobal_ButtonUploadFileImage,
import { IconCamera } from "@tabler/icons-react"; ComponentGlobal_LoadImage,
} from "@/app_modules/_global/component";
import { Center, Image, Paper, Stack } from "@mantine/core";
import { useState } from "react"; import { useState } from "react";
import { MODEL_PORTOFOLIO } from "../../model/interface";
import { ComponentPortofolio_ButtonEditLogoBisnis } from "../../component"; import { ComponentPortofolio_ButtonEditLogoBisnis } from "../../component";
import { MAX_SIZE } from "@/app_modules/_global/lib"; import { MODEL_PORTOFOLIO } from "../../model/interface";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
export default function Portofolio_EditLogoBisnis({ export default function Portofolio_EditLogoBisnis({
dataPorto, dataPorto,
@@ -26,61 +23,30 @@ export default function Portofolio_EditLogoBisnis({
return ( return (
<> <>
<Stack spacing={"xl"} px={"sm"}> <Stack spacing={"xl"} px={"sm"}>
<Paper <Stack>
p={"sm"} <Paper
style={{ p={"sm"}
backgroundColor: AccentColor.darkblue, style={{
border: `2px solid ${AccentColor.blue}`, backgroundColor: AccentColor.darkblue,
borderRadius: "10px ", border: `2px solid ${AccentColor.blue}`,
padding: "15px", borderRadius: "10px ",
color: "white", padding: "15px",
}} color: "white",
> }}
<Stack align="center"> >
{img ? ( {img ? (
<Image maw={250} alt="Image" src={img} /> <Image maw={250} alt="Image" src={img} />
) : ( ) : (
<ComponentGlobal_LoadImage fileId={dataPorto.logoId} /> <ComponentGlobal_LoadImage fileId={dataPorto.logoId} />
)} )}
</Paper>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFile}
try { onSetImage={setImg}
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())]) </Center>
); </Stack>
if (files.size > MAX_SIZE) {
ComponentGlobal_NotifikasiPeringatan(
PemberitahuanMaksimalFile
);
} else {
setImg(buffer);
setFile(files);
}
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
leftIcon={<IconCamera />}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload
</Button>
)}
</FileButton>
</Center>
</Stack>
</Paper>
<ComponentPortofolio_ButtonEditLogoBisnis <ComponentPortofolio_ButtonEditLogoBisnis
file={file as any} file={file as any}
portofolioId={dataPorto.id} portofolioId={dataPorto.id}

View File

@@ -1,29 +1,31 @@
"use client"; "use client";
import { DIRECTORY_ID } from "@/app/lib";
import { RouterHome } from "@/app/lib/router_hipmi/router_home"; import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { AccentColor, MainColor } from "@/app_modules/_global/color"; import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import { import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal, ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan, ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { emailRegex } from "@/app_modules/katalog/component/regular_expressions"; import { emailRegex } from "@/app_modules/katalog/component/regular_expressions";
import { clientLogger } from "@/util/clientLogger";
import { Button } from "@mantine/core"; import { Button } from "@mantine/core";
import _ from "lodash"; import _ from "lodash";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import funCreateNewProfile from "../../fun/fun_create_profile"; import funCreateNewProfile from "../../fun/fun_create_profile";
import { MODEL_PROFILE } from "../../model/interface"; import { MODEL_PROFILE } from "../../model/interface";
import { clientLogger } from "@/util/clientLogger";
export function Profile_ComponentCreateNewProfile({ export function Profile_ComponentCreateNewProfile({
value, value,
fotoProfileId, filePP,
backgroundProfileId, fileBG,
}: { }: {
value: MODEL_PROFILE; value: MODEL_PROFILE;
fotoProfileId: string; filePP: File;
backgroundProfileId: string; fileBG: File;
}) { }) {
const router = useRouter(); const router = useRouter();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -40,19 +42,42 @@ export function Profile_ComponentCreateNewProfile({
if (!newData.email.match(emailRegex)) if (!newData.email.match(emailRegex))
return ComponentGlobal_NotifikasiPeringatan("Format email salah"); return ComponentGlobal_NotifikasiPeringatan("Format email salah");
if (fotoProfileId == "") if (filePP == null)
return ComponentGlobal_NotifikasiPeringatan("Lengkapi foto profile"); return ComponentGlobal_NotifikasiPeringatan("Lengkapi foto profile");
if (backgroundProfileId == null) if (fileBG == null)
return ComponentGlobal_NotifikasiPeringatan( return ComponentGlobal_NotifikasiPeringatan(
"Lengkapi background profile" "Lengkapi background profile"
); );
try { try {
setLoading(true); setLoading(true);
const uploadPhoto = await funGlobal_UploadToStorage({
file: filePP,
dirId: DIRECTORY_ID.profile_foto,
});
if (!uploadPhoto.success) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const uploadBackground = await funGlobal_UploadToStorage({
file: fileBG,
dirId: DIRECTORY_ID.profile_background,
});
if (!uploadBackground.success) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const create = await funCreateNewProfile({ const create = await funCreateNewProfile({
data: newData as any, data: newData as any,
imageId: fotoProfileId, imageId: uploadPhoto.data.id,
imageBackgroundId: backgroundProfileId, imageBackgroundId: uploadBackground.data.id,
}); });
if (create.status === 201) { if (create.status === 201) {
@@ -61,16 +86,16 @@ export function Profile_ComponentCreateNewProfile({
} }
if (create.status === 400) { if (create.status === 400) {
setLoading(true); setLoading(false);
ComponentGlobal_NotifikasiGagal(create.message); ComponentGlobal_NotifikasiGagal(create.message);
} }
if (create.status === 500) { if (create.status === 500) {
setLoading(true); setLoading(false);
ComponentGlobal_NotifikasiGagal(create.message); ComponentGlobal_NotifikasiGagal(create.message);
} }
} catch (error) { } catch (error) {
setLoading(true); setLoading(false);
clientLogger.error("Error create new profile:", error); clientLogger.error("Error create new profile:", error);
} }
} }

View File

@@ -1,5 +1,6 @@
"use client"; "use client";
import { MainColor } from "@/app_modules/_global/color";
import { ComponentGlobal_ErrorInput } from "@/app_modules/_global/component"; import { ComponentGlobal_ErrorInput } from "@/app_modules/_global/component";
import { Select, Stack, TextInput } from "@mantine/core"; import { Select, Stack, TextInput } from "@mantine/core";
import { IconAt } from "@tabler/icons-react"; import { IconAt } from "@tabler/icons-react";
@@ -8,13 +9,12 @@ import { emailRegex } from "../../component/regular_expressions";
import { Profile_ComponentCreateNewProfile } from "../_component"; import { Profile_ComponentCreateNewProfile } from "../_component";
import Profile_ViewUploadBackground from "./view_upload_background"; import Profile_ViewUploadBackground from "./view_upload_background";
import Profile_ViewUploadFoto from "./view_upload_foto"; import Profile_ViewUploadFoto from "./view_upload_foto";
import { MainColor } from "@/app_modules/_global/color";
export default function CreateProfile() { export default function CreateProfile() {
const [filePP, setFilePP] = useState<File | null>(null);
const [imgPP, setImgPP] = useState<any | null>(); const [imgPP, setImgPP] = useState<any | null>();
const [fileBG, setFileBG] = useState<File | null>(null);
const [imgBG, setImgBG] = useState<any | null>(); const [imgBG, setImgBG] = useState<any | null>();
const [fotoProfileId, setFotoProfileId] = useState("");
const [backgroundProfileId, setBackgroundProfileId] = useState("");
const [value, setValue] = useState({ const [value, setValue] = useState({
name: "", name: "",
@@ -29,15 +29,15 @@ export default function CreateProfile() {
<Profile_ViewUploadFoto <Profile_ViewUploadFoto
imgPP={imgPP} imgPP={imgPP}
onSetImgPP={setImgPP} onSetImgPP={setImgPP}
fotoProfileId={fotoProfileId} filePP={filePP}
onSetFotoProfileId={setFotoProfileId} onSetFilePP={setFilePP}
/> />
<Profile_ViewUploadBackground <Profile_ViewUploadBackground
imgBG={imgBG} imgBG={imgBG}
backgroundProfileId={backgroundProfileId}
onSetImgBG={setImgBG} onSetImgBG={setImgBG}
onSetBackgroundProfileId={setBackgroundProfileId} fileBG={fileBG}
onSetFileBG={setFileBG}
/> />
<Stack mb={"lg"}> <Stack mb={"lg"}>
@@ -106,7 +106,7 @@ export default function CreateProfile() {
label: { color: MainColor.white }, label: { color: MainColor.white },
input: { backgroundColor: MainColor.white }, input: { backgroundColor: MainColor.white },
required: { color: MainColor.red }, required: { color: MainColor.red },
dropdown: { backgroundColor: MainColor.white } dropdown: { backgroundColor: MainColor.white },
}} }}
withAsterisk withAsterisk
label="Jenis Kelamin" label="Jenis Kelamin"
@@ -125,8 +125,8 @@ export default function CreateProfile() {
<Profile_ComponentCreateNewProfile <Profile_ComponentCreateNewProfile
value={value as any} value={value as any}
fotoProfileId={fotoProfileId} filePP={filePP as File}
backgroundProfileId={backgroundProfileId} fileBG={fileBG as File}
/> />
</Stack> </Stack>
</Stack> </Stack>

View File

@@ -1,38 +1,28 @@
import { DIRECTORY_ID } from "@/app/lib";
import { MainColor } from "@/app_modules/_global/color";
import { import {
ComponentGlobal_BoxInformation, ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage, ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
import { clientLogger } from "@/util/clientLogger";
import { import {
AspectRatio, AspectRatio,
Box, Box,
Button,
Center, Center,
FileButton,
Image, Image,
Stack, Stack
Text
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera, IconUpload } from "@tabler/icons-react"; import { IconPhoto } from "@tabler/icons-react";
import { useState } from "react"; import { useState } from "react";
export default function Profile_ViewUploadBackground({ export default function Profile_ViewUploadBackground({
imgBG, imgBG,
onSetImgBG, onSetImgBG,
backgroundProfileId, fileBG,
onSetBackgroundProfileId, onSetFileBG,
}: { }: {
imgBG: string; imgBG: string;
onSetImgBG: (img: string | null) => void; onSetImgBG: (img: string | null) => void;
backgroundProfileId: string; fileBG: File | null;
onSetBackgroundProfileId: (id: string) => void; onSetFileBG: (file: File | null) => void;
}) { }) {
const [isLoading, setLoading] = useState(false); const [isLoading, setLoading] = useState(false);
@@ -53,110 +43,16 @@ export default function Profile_ViewUploadBackground({
</AspectRatio> </AspectRatio>
) : ( ) : (
<Stack justify="center" align="center" h={"100%"}> <Stack justify="center" align="center" h={"100%"}>
<IconUpload color="white" /> <IconPhoto size={100} />
<Text fz={"xs"} c={"white"}>
Upload Background
</Text>
</Stack> </Stack>
)} )}
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={onSetFileBG}
try { onSetImage={onSetImgBG}
setLoading(true); />
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
// if (files.size > MAX_SIZE) {
// ComponentGlobal_NotifikasiPeringatan(
// PemberitahuanMaksimalFile
// );
// onSetImgBG(null);
// return;
// }
if (backgroundProfileId != "") {
const deleteFotoBg = await funGlobal_DeleteFileById({
fileId: backgroundProfileId,
dirId: DIRECTORY_ID.profile_background,
});
if (!deleteFotoBg.success) {
clientLogger.error(
"Client failed delete background:" +
deleteFotoBg.message
);
return;
}
if (deleteFotoBg.success) {
onSetBackgroundProfileId("");
onSetImgBG(null);
const uploadBackground = await funGlobal_UploadToStorage({
file: files,
dirId: DIRECTORY_ID.profile_background,
});
if (!uploadBackground.success) {
clientLogger.error(
"Client failed upload background:" +
uploadBackground.message
);
return;
}
if (uploadBackground.success) {
onSetBackgroundProfileId(uploadBackground.data.id);
onSetImgBG(buffer);
} else {
ComponentGlobal_NotifikasiPeringatan(
"Gagal upload background profile"
);
}
}
} else {
const uploadBackground = await funGlobal_UploadToStorage({
file: files,
dirId: DIRECTORY_ID.profile_background,
});
if (uploadBackground.success) {
onSetBackgroundProfileId(uploadBackground.data.id);
onSetImgBG(buffer);
} else {
ComponentGlobal_NotifikasiPeringatan(
"Gagal upload background profile"
);
}
}
} catch (error) {
clientLogger.error("Client error upload background:", error);
} finally {
setLoading(false);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
loading={isLoading}
loaderPosition="center"
radius={"xl"}
leftIcon={<IconCamera />}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>
</Box> </Box>

View File

@@ -1,42 +1,29 @@
import { DIRECTORY_ID } from "@/app/lib";
import { MainColor } from "@/app_modules/_global/color"; import { MainColor } from "@/app_modules/_global/color";
import { ComponentGlobal_BoxInformation } from "@/app_modules/_global/component";
import { import {
funGlobal_DeleteFileById, ComponentGlobal_BoxInformation,
funGlobal_UploadToStorage, ComponentGlobal_ButtonUploadFileImage,
} from "@/app_modules/_global/fun"; } from "@/app_modules/_global/component";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global"; import { Avatar, Box, Center, Paper, Stack } from "@mantine/core";
import { clientLogger } from "@/util/clientLogger";
import {
Avatar,
Box,
Button,
Center,
FileButton,
Paper,
Stack
} from "@mantine/core";
import { IconCamera } from "@tabler/icons-react";
import { useState } from "react"; import { useState } from "react";
export default function Profile_ViewUploadFoto({ export default function Profile_ViewUploadFoto({
imgPP, imgPP,
onSetImgPP, onSetImgPP,
fotoProfileId, filePP,
onSetFotoProfileId, onSetFilePP,
}: { }: {
imgPP: string | null | undefined; imgPP: string | null | undefined;
onSetImgPP: (img: string | null) => void; onSetImgPP: (img: string | null) => void;
fotoProfileId: string; filePP: File | null;
onSetFotoProfileId: (id: string) => void; onSetFilePP: (file: File | null) => void;
}) { }) {
const [isLoadingButton, setLoadingButton] = useState(false); const [isLoading, setLoading] = useState(false);
return ( return (
<> <>
<Box> <Box>
<Stack spacing={"lg"}> <Stack spacing={"lg"}>
<ComponentGlobal_BoxInformation informasi="Upload foto profile anda dengan ukuran maksimal file 3 MB." /> <ComponentGlobal_BoxInformation informasi="Upload foto profile anda." />
<Center> <Center>
{imgPP != undefined || imgPP != null ? ( {imgPP != undefined || imgPP != null ? (
<Paper shadow="lg" radius={"100%"}> <Paper shadow="lg" radius={"100%"}>
@@ -70,122 +57,10 @@ export default function Profile_ViewUploadFoto({
</Center> </Center>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={onSetFilePP}
try { onSetImage={onSetImgPP}
setLoadingButton(true); />
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
// if (files.size > MAX_SIZE) {
// ComponentGlobal_NotifikasiPeringatan(
// PemberitahuanMaksimalFile
// );
// onSetImgPP(null);
// return;
// }
if (fotoProfileId != "") {
try {
const deleteFotoProfile = await funGlobal_DeleteFileById({
fileId: fotoProfileId,
dirId: DIRECTORY_ID.profile_foto,
});
if (!deleteFotoProfile.success) {
clientLogger.error(
"Client failed delete photo profile:" +
deleteFotoProfile.message
);
return;
}
if (deleteFotoProfile.success) {
onSetFotoProfileId("");
onSetImgPP(null);
const uploadPhoto = await funGlobal_UploadToStorage({
file: files,
dirId: DIRECTORY_ID.profile_foto,
});
if (!uploadPhoto.success) {
clientLogger.error(
"Client failed upload photo profile::" +
uploadPhoto.message
);
return;
}
if (uploadPhoto.success) {
clientLogger.info(
"Client success upload foto profile"
);
onSetFotoProfileId(uploadPhoto.data.id);
onSetImgPP(buffer);
} else {
clientLogger.error(
"Client failed upload foto:",
uploadPhoto.message
);
ComponentGlobal_NotifikasiPeringatan(
"Gagal upload foto profile"
);
}
}
} catch (error) {
clientLogger.error("Client error upload foto:", error);
}
} else {
try {
const uploadPhoto = await funGlobal_UploadToStorage({
file: files,
dirId: DIRECTORY_ID.profile_foto,
});
if (uploadPhoto.success) {
clientLogger.info("Client success upload foto profile");
onSetFotoProfileId(uploadPhoto.data.id);
onSetImgPP(buffer);
} else {
clientLogger.error(
"Client failed upload foto:",
uploadPhoto.message
);
ComponentGlobal_NotifikasiPeringatan(
"Gagal upload foto profile"
);
}
} catch (error) {
clientLogger.error("Client error upload foto:", error);
}
}
} catch (error) {
clientLogger.error("Client error upload foto:", error);
} finally {
setLoadingButton(false);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
loading={isLoadingButton}
loaderPosition="center"
radius={"xl"}
leftIcon={<IconCamera />}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>
</Box> </Box>

View File

@@ -41,6 +41,7 @@ export default function UploadFotoProfile({
onSetImage={setImage} onSetImage={setImage}
/> />
</Center> </Center>
<Profile_ComponentButtonUpdatePhotoProfile <Profile_ComponentButtonUpdatePhotoProfile
file={file as any} file={file as any}
profileId={profile.id} profileId={profile.id}

View File

@@ -4,24 +4,27 @@ import { MainColor } from "@/app_modules/_global/color";
import { import {
ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiBerhasil,
ComponentGlobal_NotifikasiGagal, ComponentGlobal_NotifikasiGagal,
ComponentGlobal_NotifikasiPeringatan,
} from "@/app_modules/_global/notif_global"; } from "@/app_modules/_global/notif_global";
import { Button } from "@mantine/core"; import { Button } from "@mantine/core";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { map_funCreatePin } from "../../fun/create/fun_create_pin"; import { map_funCreatePin } from "../../fun/create/fun_create_pin";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import { DIRECTORY_ID } from "@/app/lib";
export function ComponentMap_ButtonSavePin({ export function ComponentMap_ButtonSavePin({
namePin, namePin,
lat, lat,
long, long,
portofolioId, portofolioId,
imageId, file,
}: { }: {
namePin: string; namePin: string;
lat: string; lat: string;
long: string; long: string;
portofolioId: string; portofolioId: string;
imageId: string; file: File;
}) { }) {
const router = useRouter(); const router = useRouter();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -30,6 +33,19 @@ export function ComponentMap_ButtonSavePin({
try { try {
setLoading(true); setLoading(true);
const uploadFile = await funGlobal_UploadToStorage({
file: file,
dirId: DIRECTORY_ID.map_image,
});
if (!uploadFile.success) {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const imageId = uploadFile.data.id;
const res = await map_funCreatePin({ const res = await map_funCreatePin({
data: { data: {
latitude: lat as any, latitude: lat as any,
@@ -45,9 +61,9 @@ export function ComponentMap_ButtonSavePin({
? (ComponentGlobal_NotifikasiBerhasil(res.message), router.back()) ? (ComponentGlobal_NotifikasiBerhasil(res.message), router.back())
: ComponentGlobal_NotifikasiGagal(res.message); : ComponentGlobal_NotifikasiGagal(res.message);
} catch (error) { } catch (error) {
console.error(error);
} finally {
setLoading(false); setLoading(false);
console.error(error);
} }
} }
@@ -57,7 +73,7 @@ export function ComponentMap_ButtonSavePin({
loading={loading} loading={loading}
my={"xl"} my={"xl"}
style={{ transition: "0.5s" }} style={{ transition: "0.5s" }}
disabled={namePin === "" || imageId == "" ? true : false} disabled={namePin === "" || file === null}
radius={"xl"} radius={"xl"}
loaderPosition="center" loaderPosition="center"
bg={MainColor.yellow} bg={MainColor.yellow}

View File

@@ -33,6 +33,17 @@ export function ComponentMap_ButtonUpdateDataMap({
setIsLoading(true); setIsLoading(true);
if (file !== null) { if (file !== null) {
const uploadFileToStorage = await funGlobal_UploadToStorage({
file: file,
dirId: DIRECTORY_ID.map_image,
});
if (!uploadFileToStorage.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const deleteLogo = await funGlobal_DeleteFileById({ const deleteLogo = await funGlobal_DeleteFileById({
fileId: data.imageId, fileId: data.imageId,
dirId: DIRECTORY_ID.map_image, dirId: DIRECTORY_ID.map_image,
@@ -43,16 +54,6 @@ export function ComponentMap_ButtonUpdateDataMap({
clientLogger.error("Error delete logo", deleteLogo.message); clientLogger.error("Error delete logo", deleteLogo.message);
} }
const uploadFileToStorage = await funGlobal_UploadToStorage({
file: file,
dirId: DIRECTORY_ID.map_image,
});
if (!uploadFileToStorage.success) {
setIsLoading(false);
ComponentGlobal_NotifikasiPeringatan("Gagal upload gambar");
return;
}
const res = await map_funEditMap({ const res = await map_funEditMap({
data: data, data: data,
fileId: uploadFileToStorage.data.id, fileId: uploadFileToStorage.data.id,
@@ -91,7 +92,7 @@ export function ComponentMap_ButtonUpdateDataMap({
loading={isLoading} loading={isLoading}
mb={"xl"} mb={"xl"}
style={{ transition: "0.5s" }} style={{ transition: "0.5s" }}
disabled={data.namePin === "" ? true : false} disabled={data.namePin === "" || file === null}
radius={"xl"} radius={"xl"}
bg={MainColor.yellow} bg={MainColor.yellow}
color="yellow" color="yellow"

View File

@@ -1,10 +1,19 @@
"use client"; "use client";
import { DIRECTORY_ID } from "@/app/lib";
import { import {
AccentColor, AccentColor,
MainColor, MainColor,
} from "@/app_modules/_global/color/color_pallet"; } from "@/app_modules/_global/color/color_pallet";
import { ComponentGlobal_BoxUploadImage } from "@/app_modules/_global/component"; import {
ComponentGlobal_BoxInformation,
ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
} from "@/app_modules/_global/component";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { MAX_SIZE } from "@/app_modules/_global/lib"; import { MAX_SIZE } from "@/app_modules/_global/lib";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size"; import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan"; import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
@@ -16,11 +25,9 @@ import {
Image, Image,
Paper, Paper,
Stack, Stack,
Text,
TextInput, TextInput,
Title,
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera } from "@tabler/icons-react"; import { IconCamera, IconPhoto } from "@tabler/icons-react";
import _ from "lodash"; import _ from "lodash";
import { useState } from "react"; import { useState } from "react";
import Map, { import Map, {
@@ -31,11 +38,6 @@ import Map, {
} from "react-map-gl"; } from "react-map-gl";
import { ComponentMap_ButtonSavePin } from "../_component"; import { ComponentMap_ButtonSavePin } from "../_component";
import { defaultLatLong, defaultMapZoom } from "../lib/default_lat_long"; import { defaultLatLong, defaultMapZoom } from "../lib/default_lat_long";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { DIRECTORY_ID } from "@/app/lib";
export function UiMap_CreatePin({ export function UiMap_CreatePin({
mapboxToken, mapboxToken,
@@ -47,85 +49,92 @@ export function UiMap_CreatePin({
const [[lat, long], setLatLong] = useState([0, 0]); const [[lat, long], setLatLong] = useState([0, 0]);
const [isPin, setIsPin] = useState(false); const [isPin, setIsPin] = useState(false);
const [namePin, setNamePin] = useState(""); const [namePin, setNamePin] = useState("");
const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>(null); const [img, setImg] = useState<any | null>(null);
const [imageId, setImageId] = useState("");
return ( return (
<> <>
<Stack> <Stack spacing={50}>
<Map {/* Map Pin */}
mapboxAccessToken={mapboxToken} <Stack spacing={"sm"}>
mapStyle={"mapbox://styles/mapbox/streets-v11"} <ComponentGlobal_BoxInformation informasi="Tentukan lokasi pin map dengan klik pada peta." />
initialViewState={{ <Map
latitude: defaultLatLong[0], mapboxAccessToken={mapboxToken}
longitude: defaultLatLong[1], mapStyle={"mapbox://styles/mapbox/streets-v11"}
zoom: defaultMapZoom, initialViewState={{
}} latitude: defaultLatLong[0],
style={{ longitude: defaultLatLong[1],
cursor: "pointer", zoom: defaultMapZoom,
width: "100%", }}
height: "60vh",
borderRadius: "10px",
}}
onClick={(a) => {
setLatLong([a.lngLat.lat, a.lngLat.lng]);
setIsPin(true);
}}
attributionControl={false}
>
<Marker
style={{ style={{
color: "red",
width: 40,
// height: 40,
cursor: "pointer", cursor: "pointer",
width: "100%",
height: "60vh",
borderRadius: "10px",
}} }}
latitude={lat} onClick={(a) => {
longitude={long} setLatLong([a.lngLat.lat, a.lngLat.lng]);
anchor="bottom" setIsPin(true);
}}
attributionControl={false}
> >
<Stack spacing={0}> <Marker
<Image style={{
w={"100%"} color: "red",
alt="image" width: 40,
src="https://cdn-icons-png.flaticon.com/512/5860/5860579.png" // height: 40,
/> cursor: "pointer",
</Stack> }}
</Marker> latitude={lat}
<NavigationControl /> longitude={long}
<ScaleControl position="top-left" /> anchor="bottom"
<AttributionControl customAttribution="Map design by PT. Bali Interaktif Perkasa" /> >
</Map> <Stack spacing={0}>
<Image
w={"100%"}
alt="image"
src="https://cdn-icons-png.flaticon.com/512/5860/5860579.png"
/>
</Stack>
</Marker>
<NavigationControl />
<ScaleControl position="top-left" />
<AttributionControl customAttribution="Map design by PT. Bali Interaktif Perkasa" />
</Map>
<Paper <Paper
style={{ style={{
padding: "15px", padding: "15px",
backgroundColor: AccentColor.darkblue, backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`, border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px", borderRadius: "10px",
color: "white", color: "white",
}}
>
<TextInput
disabled={isPin ? false : true}
style={{ transition: "0.5s" }}
styles={{ label: { color: isPin ? MainColor.white : "gray" },
input: {
backgroundColor: MainColor.white
},
required: {
color: MainColor.red,
} }}
label="Nama Pin"
placeholder="Masukan nama pin map"
withAsterisk
onChange={(val) => {
setNamePin(_.startCase(val.currentTarget.value));
}} }}
/> >
</Paper> <TextInput
disabled={isPin ? false : true}
style={{ transition: "0.5s" }}
styles={{
label: { color: isPin ? MainColor.white : "gray" },
input: {
backgroundColor: MainColor.white,
},
required: {
color: MainColor.red,
},
}}
label="Nama Pin"
placeholder="Masukan nama pin map"
withAsterisk
onChange={(val) => {
setNamePin(_.startCase(val.currentTarget.value));
}}
/>
</Paper>
</Stack>
<Stack> <Stack spacing={"sm"}>
<ComponentGlobal_BoxInformation informasi="Upload foto lokasi bisnis anda untuk ditampilkan dalam detail map." />
<ComponentGlobal_BoxUploadImage> <ComponentGlobal_BoxUploadImage>
{img ? ( {img ? (
<AspectRatio ratio={1 / 1} mah={265} mx={"auto"}> <AspectRatio ratio={1 / 1} mah={265} mx={"auto"}>
@@ -138,100 +147,16 @@ export function UiMap_CreatePin({
</AspectRatio> </AspectRatio>
) : ( ) : (
<Stack spacing={5} justify="center" align="center" h={"100%"}> <Stack spacing={5} justify="center" align="center" h={"100%"}>
<Title c={MainColor.white} order={3}>Foto Lokasi Bisnis</Title> <IconPhoto size={100} />
<Text c={MainColor.white} fs={"italic"} fz={10} align="center">
Upload foto lokasi bisnis anda untuk ditampilkan dalam detail
map
</Text>
</Stack> </Stack>
)} )}
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFile}
try { onSetImage={setImg}
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())])
);
if (files.size > MAX_SIZE) {
setImg(null);
ComponentGlobal_NotifikasiPeringatan(
PemberitahuanMaksimalFile,
3000
);
return;
}
// if (files.size > MAX_SIZE) {
// setImg(null);
// ComponentGlobal_NotifikasiPeringatan(
// PemberitahuanMaksimalFile,
// 3000
// );
// } else {
// setImg(buffer);
// }
if (imageId != "") {
const deletePhoto = await funGlobal_DeleteFileById({
fileId: imageId,
});
if (deletePhoto.success) {
setImageId("");
const uploadPhoto = await funGlobal_UploadToStorage({
file: files,
dirId: DIRECTORY_ID.map_image,
});
if (uploadPhoto.success) {
setImageId(uploadPhoto.data.id);
setImg(buffer);
} else {
ComponentGlobal_NotifikasiPeringatan(
"Gagal upload gambar"
);
}
}
} else {
const uploadPhoto = await funGlobal_UploadToStorage({
file: files,
dirId: DIRECTORY_ID.map_image,
});
if (uploadPhoto.success) {
setImageId(uploadPhoto.data.id);
setImg(buffer);
} else {
ComponentGlobal_NotifikasiPeringatan(
"Gagal upload gambar"
);
}
}
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
disabled={isPin ? false : true}
{...props}
radius={"xl"}
leftIcon={<IconCamera />}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>
@@ -240,7 +165,7 @@ export function UiMap_CreatePin({
lat={lat as any} lat={lat as any}
long={long as any} long={long as any}
portofolioId={portofolioId} portofolioId={portofolioId}
imageId={imageId} file={file as File}
/> />
</Stack> </Stack>
</> </>

View File

@@ -1,18 +1,22 @@
"use client"; "use client";
import { RouterPortofolio } from "@/app/lib/router_hipmi/router_katalog"; import { APIs, DIRECTORY_ID } from "@/app/lib";
import { RouterMap } from "@/app/lib/router_hipmi/router_map";
import { import {
AccentColor, AccentColor,
MainColor, MainColor,
} from "@/app_modules/_global/color/color_pallet"; } from "@/app_modules/_global/color/color_pallet";
import { ComponentGlobal_ButtonUploadFileImage } from "@/app_modules/_global/component";
import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information"; import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information";
import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data"; import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil"; import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal"; import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan"; import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
import { Avatar, Button, Center, FileButton, Stack } from "@mantine/core"; import { clientLogger } from "@/util/clientLogger";
import { IconCamera } from "@tabler/icons-react"; import { Avatar, Button, Center, Stack } from "@mantine/core";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { import {
@@ -25,14 +29,6 @@ import {
import { map_funCustomPinMap } from "../fun"; import { map_funCustomPinMap } from "../fun";
import { defaultMapZoom } from "../lib/default_lat_long"; import { defaultMapZoom } from "../lib/default_lat_long";
import { MODEL_MAP } from "../lib/interface"; import { MODEL_MAP } from "../lib/interface";
import { APIs, DIRECTORY_ID } from "@/app/lib";
import {
funGlobal_DeleteFileById,
funGlobal_UploadToStorage,
} from "@/app_modules/_global/fun";
import { MAX_SIZE } from "@/app_modules/_global/lib";
import { PemberitahuanMaksimalFile } from "@/app_modules/_global/lib/max_size";
import { clientLogger } from "@/util/clientLogger";
export function UiMap_CustomPin({ export function UiMap_CustomPin({
dataMap, dataMap,
@@ -55,7 +51,7 @@ export function UiMap_CustomPin({
<Stack> <Stack>
<ComponentGlobal_BoxInformation <ComponentGlobal_BoxInformation
informasi={ informasi={
"Pin map akan secara otomatis menampilkan logo pada porotofolio ini, jika anda ingin melakukan custom silahkan upload logo pin baru anda !" "Pin map akan secara otomatis menampilkan logo pada porotofolio ini, jika anda ingin melakukan custom silahkan upload logo pin baru anda."
} }
/> />
@@ -90,40 +86,10 @@ export function UiMap_CustomPin({
)} )}
<Center> <Center>
<FileButton <ComponentGlobal_ButtonUploadFileImage
onChange={async (files: any | null) => { onSetFile={setFilePin}
try { onSetImage={setImgPin}
const buffer = URL.createObjectURL( />
new Blob([new Uint8Array(await files.arrayBuffer())])
);
if (files.size > MAX_SIZE) {
ComponentGlobal_NotifikasiPeringatan(
PemberitahuanMaksimalFile,
3000
);
} else {
setImgPin(buffer);
setFilePin(files);
}
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
leftIcon={<IconCamera />}
bg={MainColor.yellow}
color="yellow"
c={"black"}
>
Upload
</Button>
)}
</FileButton>
</Center> </Center>
</Stack> </Stack>
@@ -201,14 +167,6 @@ function ButtonSimpan({
async function onCustom() { async function onCustom() {
try { try {
setLoading(true); setLoading(true);
const deletePin = await funGlobal_DeleteFileById({
fileId: fileRemoveId,
dirId: DIRECTORY_ID.map_pin,
});
if (!deletePin.success) {
setLoading(false);
clientLogger.error("Error delete logo", deletePin.message);
}
const uploadFileToStorage = await funGlobal_UploadToStorage({ const uploadFileToStorage = await funGlobal_UploadToStorage({
file: filePin, file: filePin,
@@ -221,6 +179,15 @@ function ButtonSimpan({
return; return;
} }
const deletePin = await funGlobal_DeleteFileById({
fileId: fileRemoveId,
dirId: DIRECTORY_ID.map_pin,
});
if (!deletePin.success) {
setLoading(false);
clientLogger.error("Error delete logo", deletePin.message);
}
const res = await map_funCustomPinMap({ const res = await map_funCustomPinMap({
mapId: mapId, mapId: mapId,
fileId: uploadFileToStorage.data.id, fileId: uploadFileToStorage.data.id,

View File

@@ -7,6 +7,7 @@ import {
} from "@/app_modules/_global/color/color_pallet"; } from "@/app_modules/_global/color/color_pallet";
import { import {
ComponentGlobal_BoxUploadImage, ComponentGlobal_BoxUploadImage,
ComponentGlobal_ButtonUploadFileImage,
ComponentGlobal_LoadImage, ComponentGlobal_LoadImage,
} from "@/app_modules/_global/component"; } from "@/app_modules/_global/component";
import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information"; import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information";
@@ -49,89 +50,100 @@ export function UiMap_EditMap({
return ( return (
<> <>
<Stack spacing={30} px={"sm"}> <Stack spacing={50} px={"sm"}>
<Map <Stack spacing={"sm"}>
mapboxAccessToken={mapboxToken} <ComponentGlobal_BoxInformation informasi="Tentukan lokasi pin map dengan klik pada peta." />
mapStyle={"mapbox://styles/mapbox/streets-v11"}
initialViewState={{ <Map
latitude: data.latitude, mapboxAccessToken={mapboxToken}
longitude: data.longitude, mapStyle={"mapbox://styles/mapbox/streets-v11"}
zoom: defaultMapZoom, initialViewState={{
}} latitude: data.latitude,
style={{ longitude: data.longitude,
cursor: "pointer", zoom: defaultMapZoom,
width: "100%",
height: "60vh",
borderRadius: "10px",
}}
onClick={(a) => {
setData({
...data,
latitude: a.lngLat.lat,
longitude: a.lngLat.lng,
});
}}
attributionControl={false}
>
<Marker
style={{
color: "red",
width: 40,
// height: 40,
cursor: "pointer",
}} }}
latitude={data.latitude} style={{
longitude={data.longitude} cursor: "pointer",
anchor="bottom" width: "100%",
> height: "60vh",
<Avatar borderRadius: "10px",
src={ }}
data.pinId === null onClick={(a) => {
? APIs.GET({ fileId: dataMap.Portofolio.logoId, size: "400" })
: APIs.GET({ fileId: data.pinId, size: "400" })
}
alt="Logo"
style={{
border: `2px solid ${AccentColor.softblue}`,
backgroundColor: "white",
borderRadius: "100%",
}}
/>
</Marker>
<NavigationControl />
<ScaleControl position="top-left" />
<AttributionControl customAttribution="Map design by PT. Bali Interaktif Perkasa" />
</Map>
<Paper
style={{
padding: "15px",
backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px",
color: "white",
}}
>
<TextInput
style={{ transition: "0.5s", }}
styles={{ label: { color: MainColor.white }, required: { color: MainColor.red }, input: { backgroundColor: MainColor.white } }}
label="Nama Pin"
placeholder="Masukan nama pin map"
value={data.namePin}
withAsterisk
onChange={(val) => {
setData({ setData({
...data, ...data,
namePin: val.currentTarget.value, latitude: a.lngLat.lat,
longitude: a.lngLat.lng,
}); });
}} }}
/> attributionControl={false}
</Paper> >
<Marker
style={{
color: "red",
width: 40,
// height: 40,
cursor: "pointer",
}}
latitude={data.latitude}
longitude={data.longitude}
anchor="bottom"
>
<Avatar
src={
data.pinId === null
? APIs.GET({
fileId: dataMap.Portofolio.logoId,
size: "400",
})
: APIs.GET({ fileId: data.pinId, size: "400" })
}
alt="Logo"
style={{
border: `2px solid ${AccentColor.softblue}`,
backgroundColor: "white",
borderRadius: "100%",
}}
/>
</Marker>
<NavigationControl />
<ScaleControl position="top-left" />
<AttributionControl customAttribution="Map design by PT. Bali Interaktif Perkasa" />
</Map>
<Paper
style={{
padding: "15px",
backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px",
color: "white",
}}
>
<TextInput
style={{ transition: "0.5s" }}
styles={{
label: { color: MainColor.white },
required: { color: MainColor.red },
input: { backgroundColor: MainColor.white },
}}
label="Nama Pin"
placeholder="Masukan nama pin map"
value={data.namePin}
withAsterisk
onChange={(val) => {
setData({
...data,
namePin: val.currentTarget.value,
});
}}
/>
</Paper>
</Stack>
{/* Photo Usaha */} {/* Photo Usaha */}
<Stack spacing={"xs"}> <Stack spacing={"xs"}>
<ComponentGlobal_BoxInformation informasi="Masukan photo toko atau tempat usaha anda !" /> <ComponentGlobal_BoxInformation informasi="Upload foto lokasi bisnis anda untuk ditampilkan dalam detail map." />
<ComponentGlobal_BoxUploadImage> <ComponentGlobal_BoxUploadImage>
{img ? ( {img ? (
@@ -144,6 +156,13 @@ export function UiMap_EditMap({
</ComponentGlobal_BoxUploadImage> </ComponentGlobal_BoxUploadImage>
<Center> <Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={setFile}
onSetImage={setImg}
/>
</Center>
{/* <Center>
<FileButton <FileButton
onChange={async (files: any | null) => { onChange={async (files: any | null) => {
try { try {
@@ -178,7 +197,7 @@ export function UiMap_EditMap({
</Button> </Button>
)} )}
</FileButton> </FileButton>
</Center> </Center> */}
</Stack> </Stack>
<ComponentMap_ButtonUpdateDataMap data={data as any} file={file} /> <ComponentMap_ButtonUpdateDataMap data={data as any} file={file} />

View File

@@ -22,19 +22,19 @@ const middlewareConfig: MiddlewareConfig = {
// registarasiPath: "/register", // registarasiPath: "/register",
userPath: "/dev/home", userPath: "/dev/home",
publicRoutes: [ publicRoutes: [
// API // API
"/", "/",
"/api/voting/*", "/api/voting/*",
"/api/collaboration/*", "/api/collaboration/*",
"/api/notifikasi/*", "/api/notifikasi/*",
"/api/logs/*", "/api/logs/*",
"/api/image/*",
"/api/job/*", "/api/job/*",
"/api/auth/*", "/api/auth/*",
"/api/origin-url", "/api/origin-url",
// "/api/user",
"/api/event/*", "/api/event/*",
// "/api/image/*",
// "/api/user",
"/api/new/*",
// Akses awal // Akses awal
"/api/get-cookie", "/api/get-cookie",
"/api/user/activation", "/api/user/activation",
@@ -103,7 +103,7 @@ export const middleware = async (req: NextRequest) => {
if ( if (
isPublicRoute && isPublicRoute &&
pathname !== loginPath pathname !== loginPath
// && // &&
// pathname !== validasiPath && // pathname !== validasiPath &&
// pathname !== registarasiPath // pathname !== registarasiPath

44
xhtml/index.html Normal file
View File

@@ -0,0 +1,44 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- <img
id="pdf"
src="https://wibu-storage.wibudev.com/api/pdf-to-image?url=https://pdfobject.com/pdf/sample.pdf"
alt="pdf"
/> -->
<div id="pdfs"></div>
</body>
<script type="module">
(async () => {
const imagePdf = document.getElementById("pdf");
const pdfs = document.getElementById("pdfs");
const token =
"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjp7ImlkIjoiY20wdXIxeXh3MDAwMDU2bnNqbHI2MTg3cCIsIm5hbWUiOiJiYWdhcyIsImVtYWlsIjoiYmFnYXNAZ21haWwuY29tIn0sImlhdCI6MTcyNTg3MTAzNiwiZXhwIjo0ODgxNjMxMDM2fQ.wFQLcrJj66wFeqIMYk2esMx3ULaHK6RFxkiToaLCuko";
const res = await fetch(
"https://wibu-storage.wibudev.com/api/pdf-to-image?url=https://wibu-storage.wibudev.com/api/files/cm5jgzg7d001dxpugxseb2ua0",
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}
);
const jsonData = await res.json();
// console.log(JSON.stringify(jsonData.pages, null, 2));
// imagePdf.src = jsonData.pages[0].imageUrl;
for (let index = 0; index < jsonData.pages.length; index++) {
const element = jsonData.pages[index];
const img = document.createElement("img");
img.src = element.imageUrl;
pdfs.appendChild(img);
}
})();
</script>
</html>