Merge pull request #238 from bipproduction/bagas/13-jan-25

Fix uploaded image : Profile, Portofolio, Job
This commit is contained in:
Bagasbanuna02
2025-01-14 11:02:59 +08:00
committed by GitHub
32 changed files with 593 additions and 879 deletions

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

@@ -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,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

@@ -20,8 +20,8 @@ if (process.env.NODE_ENV !== "production") {
} }
process.on("SIGINT", async () => { process.on("SIGINT", async () => {
console.log("Disconnecting PrismaClient..."); // console.log("Disconnecting PrismaClient...");
await prisma.$disconnect();3 await prisma.$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,15 +2,16 @@
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,
}: { }: {
onSetFile: File | any; onSetFile: File | null | any;
onSetImage: any | null; onSetImage: any | null;
}) { }) {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -24,20 +25,20 @@ 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 { }
// }
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="image/png,image/png,image/jpeg,image/gif"
> >
{(props) => ( {(props) => (
<Button <Button
@@ -45,10 +46,12 @@ 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={<IconUpload color="black" size={20} />}
c={MainColor.darkblue}
> >
Upload Upload
</Button> </Button>

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,18 @@ 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} />
</Grid.Col>
<Grid.Col span={10}>
<Text span inherit c={MainColor.white} fw={"normal"}> <Text 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) {
throw new Error("Failed to get token");
}
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

@@ -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

@@ -10,28 +10,25 @@ import {
Text, Text,
TextInput, TextInput,
} from "@mantine/core"; } from "@mantine/core";
import { IconCamera, IconUpload } from "@tabler/icons-react"; import { IconCamera } 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 { import {
AccentColor, AccentColor,
MainColor, MainColor,
} from "@/app_modules/_global/color/color_pallet"; } 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 +48,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 +63,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,35 @@
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 { clientLogger } from "@/util/clientLogger";
import { import {
Avatar, Avatar,
Box, Box,
Button,
Center, Center,
FileButton,
Paper, Paper,
Stack Stack
} from "@mantine/core"; } 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,6 +63,13 @@ export default function Profile_ViewUploadFoto({
</Center> </Center>
<Center> <Center>
<ComponentGlobal_ButtonUploadFileImage
onSetFile={onSetFilePP}
onSetImage={onSetImgPP}
/>
</Center>
{/* <Center>
<FileButton <FileButton
onChange={async (files: any | null) => { onChange={async (files: any | null) => {
try { try {
@@ -186,7 +186,7 @@ export default function Profile_ViewUploadFoto({
</Button> </Button>
)} )}
</FileButton> </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

@@ -29,7 +29,7 @@ const middlewareConfig: MiddlewareConfig = {
"/api/collaboration/*", "/api/collaboration/*",
"/api/notifikasi/*", "/api/notifikasi/*",
"/api/logs/*", "/api/logs/*",
"/api/image/*", // "/api/image/*",
"/api/job/*", "/api/job/*",
"/api/auth/*", "/api/auth/*",
"/api/origin-url", "/api/origin-url",