QC Profile

# fix bug
- Kapasitas foto profile
- Kapasistas gambar background
- Cek email invalid
- Server action untuk profile (tidak menggunakan API lagi)
### No Issuee
This commit is contained in:
2024-03-12 10:16:04 +08:00
parent 629fd601d4
commit 7baceafa80
37 changed files with 679 additions and 321 deletions

View File

@@ -15,6 +15,7 @@
"@mantine/core": "^6.0.17",
"@mantine/dates": "^6.0.17",
"@mantine/dropzone": "^7.1.3",
"@mantine/form": "^7.6.1",
"@mantine/hooks": "^6.0.17",
"@mantine/next": "^6.0.17",
"@mantine/notifications": "^6.0.17",

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -9,7 +9,7 @@ export default async function Page() {
const userId = await User_getUserId();
const dataUser = await user_getOneById(userId);
// await new Promise((a, b) => {
// setTimeout(a, 1000);
// setTimeout(a, 4000);
// });
return (

View File

@@ -23,9 +23,9 @@ export default async function Page({ params }: { params: { id: string } }) {
const dataProfile = await Profile_getOneProfileAndUserById(profileId);
// console.log(dataProfile)
await new Promise((a, b) => {
setTimeout(a, 1000);
});
// await new Promise((a, b) => {
// setTimeout(a, 1000);
// });
return (
<>

View File

@@ -0,0 +1,9 @@
import ComponentGlobal_V2_LoadingPage from "@/app_modules/component_global/loading_page_v2";
export default async function Page() {
return (
<>
<ComponentGlobal_V2_LoadingPage />
</>
);
}

View File

@@ -1,19 +1,51 @@
"use client";
import { NotifPeringatan } from "@/app_modules/donasi/component/notifikasi/notif_peringatan";
import { Box, Button, Group } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import {
Box,
Center,
Group,
LoadingOverlay,
Paper,
Skeleton,
Text,
} from "@mantine/core";
export default function ComponentCobaCoba_LoadingPage() {
const listhHuruf = [
{
huruf: "H",
},
{
huruf: "I",
},
{
huruf: "P",
},
{
huruf: "M",
},
{
huruf: "I",
},
];
const customLOader = (
<Center h={"100vh"}>
<Group>
{listhHuruf.map((e, i) => (
<Center key={i} h={"100%"}>
<Skeleton height={50} circle radius={"100%"} />
<Text sx={{ position: "absolute" }} c={"gray.4"} fw={"bold"}>
{e.huruf}
</Text>
</Center>
))}
</Group>
</Center>
);
export default function Coba() {
return (
<>
<Box p={"lg"}>
<Group position="center">
<Button variant="outline" onClick={() => NotifPeringatan("Coba")}>
Show notification
</Button>
</Group>
</Box>
<LoadingOverlay visible overlayBlur={2} loader={customLOader} />
</>
);
}

View File

@@ -9,9 +9,8 @@ export async function auth_Logout(kodeId: string) {
name: "ssn",
value: "",
maxAge: 0,
path: "/dev/auth/login",
});
const c = cookies().get("ssn");
if (c?.value !== "") return { status: 400, message: "Gagal Logout" };

View File

@@ -20,25 +20,14 @@ export default function User_Logout() {
const [loading, setLoading] = useState(false);
const [loading2, setLoading2] = useState(false);
const onLogout = async () => {
// await fetch(ApiHipmi.logout)
// .then((res) => res.json())
// .then((val) => {
// if (val.status == 200) {
// setnomor(null);
// setCode(null);
// ComponentGlobal_NotifikasiBerhasil("Anda Berhasil Logout")
// return router.push("/dev/auth/login");
// }
// });
};
async function onClickLogout() {
// await auth_Logout(kodeId).then((res) => {
// ComponentGlobal_NotifikasiBerhasil("Berhasil Logout");
// });
await auth_Logout(kodeId).then((res) => {
if (res.status === 200) {
setKodeId("");
ComponentGlobal_NotifikasiBerhasil(res.message);
router.push(RouterAuth.login)
setKodeId("");
} else {
ComponentGlobal_NotifikasiPeringatan(res.message);
}

View File

@@ -1,25 +1,43 @@
"use client";
import { Box, Center, Group, LoadingOverlay, Skeleton } from "@mantine/core";
import { Box, Center, Group, LoadingOverlay, Skeleton, Text } from "@mantine/core";
export default function ComponentGlobal_V2_LoadingPage() {
const customLOader = (
<Center h={"100vh"}>
<Group>
{Array(3)
.fill(0)
.map((e, i) => (
<Skeleton key={i} height={50} circle mb="xl" />
))}
</Group>
</Center>
);
const listhHuruf = [
{
huruf: "H",
},
{
huruf: "I",
},
{
huruf: "P",
},
{
huruf: "M",
},
{
huruf: "I",
},
];
const customLOader = (
<Center h={"100vh"}>
<Group>
{listhHuruf.map((e, i) => (
<Center key={i} h={"100%"}>
<Skeleton height={50} circle radius={"100%"} />
<Text sx={{ position: "absolute" }} c={"gray.4"} fw={"bold"}>
{e.huruf}
</Text>
</Center>
))}
</Group>
</Center>
);
return (
<>
<LoadingOverlay visible overlayBlur={2} loader={customLOader} />
</>
);
return (
<>
<LoadingOverlay visible overlayBlur={1} loader={customLOader} />
</>
);
}

View File

@@ -59,10 +59,10 @@ export default function Forum_Komentar({ forumId }: { forumId: string }) {
}}
/>
</Paper>
<Group position="apart">
<ActionIcon>
<Group position="right">
{/* <ActionIcon>
<IconPhotoUp />
</ActionIcon>
</ActionIcon> */}
<ButtonAction forumId={forumId} />
</Group>
</Stack>

View File

@@ -10,7 +10,7 @@ const config = yaml.parse(fs.readFileSync("config.yaml").toString());
export async function User_getUserId() {
const c = cookies().get("ssn");
if (!c?.value) return redirect(RouterAuth.login);
if (!c?.value || c.value === "") return redirect(RouterAuth.login);
const token = JSON.parse(

View File

@@ -41,6 +41,7 @@ export default function HomeLayout({
const router = useRouter();
const [user, setUser] = useState(dataUser);
const [loading, setLoading] = useState(false);
const [loadingUS, setLoadingUS] = useState(false);
const listFooter = [
{
id: 1,
@@ -88,19 +89,26 @@ export default function HomeLayout({
if (user?.Profile === null) {
ComponentGlobal_NotifikasiPeringatan("Lengkapi Profile");
} else {
setLoadingUS(true);
// router.push(RouterProfile.katalog + `${user.Profile.id}`);
router.push(RouterUserSearch.main);
}
}}
>
<Stack align="center" spacing={0}>
<ActionIcon variant={"transparent"}>
<IconUserSearch color="white" />
</ActionIcon>
<Text fz={"xs"} c={"white"}>
Temukan pengguna
</Text>
</Stack>
{loadingUS ? (
<Center>
<Loader />
</Center>
) : (
<Stack align="center" spacing={0}>
<ActionIcon variant={"transparent"}>
<IconUserSearch color="white" />
</ActionIcon>
<Text fz={"xs"} c={"white"}>
Temukan pengguna
</Text>
</Stack>
)}
</Grid.Col>
<Grid.Col
span={"auto"}
@@ -113,32 +121,36 @@ export default function HomeLayout({
}
}}
>
<Stack align="center" spacing={2}>
<ActionIcon variant={"transparent"}>
{user?.Profile === null ? (
<IconUserCircle color="white" />
) : loading ? (
<Loader />
) : (
<Avatar
radius={"xl"}
size={30}
sx={{
borderStyle: "solid",
borderWidth: "0.5px",
borderColor: "white",
}}
src={
RouterProfile.api_foto_profile +
`${user?.Profile.imagesId}`
}
/>
)}
</ActionIcon>
<Text fz={"xs"} c={"white"}>
Profile
</Text>
</Stack>
{loading ? (
<Center>
<Loader />
</Center>
) : (
<Stack align="center" spacing={2}>
<ActionIcon variant={"transparent"}>
{user?.Profile === null ? (
<IconUserCircle color="white" />
) : (
<Avatar
radius={"xl"}
size={30}
sx={{
borderStyle: "solid",
borderWidth: "0.5px",
borderColor: "white",
}}
src={
RouterProfile.api_foto_profile +
`${user?.Profile.imagesId}`
}
/>
)}
</ActionIcon>
<Text fz={"xs"} c={"white"}>
Profile
</Text>
</Stack>
)}
</Grid.Col>
</Grid>
</Footer>

View File

@@ -1,5 +1,6 @@
"use client";
import ComponentGlobal_HeaderTamplate from "@/app_modules/component_global/header_tamplate";
import {
ActionIcon,
AppShell,
@@ -18,15 +19,16 @@ export default function ProfileLayout({ children }: { children: any }) {
<AppShell
header={
<Header height={50} px={"sm"} sx={{borderBlockStyle: "none"}}>
<Group position="apart" h={50}>
<ActionIcon variant="transparent" onClick={() => router.push("/dev/home")}>
<IconArrowLeft />
</ActionIcon>
<Text>Create Profile</Text>
<ActionIcon variant="transparent"></ActionIcon>
</Group>
</Header>
// <Header height={50} px={"sm"} sx={{borderBlockStyle: "none"}}>
// <Group position="apart" h={50}>
// <ActionIcon variant="transparent" onClick={() => router.push("/dev/home")}>
// <IconArrowLeft />
// </ActionIcon>
// <Text>Create Profile</Text>
// <ActionIcon variant="transparent"></ActionIcon>
// </Group>
// </Header>
<ComponentGlobal_HeaderTamplate title="Buat Profile"/>
}
>
{children}

View File

@@ -14,6 +14,7 @@ import {
Paper,
Select,
Stack,
Text,
TextInput,
} from "@mantine/core";
import { useAtom } from "jotai";
@@ -22,7 +23,7 @@ import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-simple-toasts";
import funCreateNewProfile from "../fun/fun_create_profile";
import { IconCamera } from "@tabler/icons-react";
import { IconAt, IconCamera, IconUpload } from "@tabler/icons-react";
import ComponentKatalog_NotedBox from "../../component/noted_box";
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
import { MODEL_PROFILE } from "../model/interface";
@@ -31,9 +32,9 @@ import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/component_glob
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { useForm } from "@mantine/form";
export default function CreateProfile({ userId }: { userId: any }) {
const router = useRouter();
const [filePP, setFilePP] = useState<File | null>(null);
const [imgPP, setImgPP] = useState<any | null>();
const [fileBG, setFileBG] = useState<File | null>(null);
@@ -53,16 +54,32 @@ export default function CreateProfile({ userId }: { userId: any }) {
<Stack>
<ComponentKatalog_NotedBox informasi="Upload foto profile anda." />
<Center>
<Avatar
sx={{
borderStyle: "solid",
borderColor: "black",
borderWidth: "1px",
}}
src={imgPP ? imgPP : "/aset/global/avatar.png"}
size={150}
radius={"100%"}
/>
{imgPP ? (
<Paper shadow="lg" radius={"100%"}>
<Avatar
sx={{
borderStyle: "solid",
borderColor: "gray",
borderWidth: "0.5px",
}}
src={imgPP ? imgPP : "/aset/global/avatar.png"}
size={150}
radius={"100%"}
/>
</Paper>
) : (
<Paper shadow="lg" radius={"100%"}>
<Avatar
size={150}
radius={"100%"}
sx={{
borderStyle: "solid",
borderColor: "gray",
borderWidth: "0.5px",
}}
/>
</Paper>
)}
</Center>
<Center>
<FileButton
@@ -71,10 +88,17 @@ export default function CreateProfile({ userId }: { userId: any }) {
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
if (files.size > 1000000) {
ComponentGlobal_NotifikasiPeringatan(
"Maaf, Ukuran file terlalu besar, maximum 1mb",
3000
);
} else {
setImgPP(buffer);
setFilePP(files);
}
// console.log(buffer, "ini buffer");
// console.log(files, " ini file");
setImgPP(buffer);
setFilePP(files);
} catch (error) {
console.log(error);
}
@@ -104,13 +128,25 @@ export default function CreateProfile({ userId }: { userId: any }) {
<AspectRatio ratio={16 / 9}>
<Paper
radius={"md"}
sx={{
borderStyle: "solid",
borderColor: "black",
borderWidth: "1px",
}}
withBorder
shadow="lg"
bg={"gray.2"}
// sx={{
// borderStyle: "solid",
// borderColor: "black",
// borderWidth: "1px",
// }}
>
<Image alt="Foto" src={imgBG ? imgBG : "/aset/no-img.png"} />
{imgBG ? (
<Image alt="Foto" src={imgBG ? imgBG : "/aset/no-img.png"} />
) : (
<Stack align="center">
<IconUpload color="gray" />
<Text fz={"xs"} c={"gray"}>
Upload Background
</Text>
</Stack>
)}
</Paper>
</AspectRatio>
@@ -121,10 +157,17 @@ export default function CreateProfile({ userId }: { userId: any }) {
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
if (files.size > 1000000) {
ComponentGlobal_NotifikasiPeringatan(
"Maaf, Ukuran file terlalu besar, maximum 1mb",
3000
);
} else {
setImgBG(buffer);
setFileBG(files);
}
// console.log(buffer, "ini buffer");
// console.log(files, " ini file");
setImgBG(buffer);
setFileBG(files);
} catch (error) {
console.log(error);
}
@@ -148,96 +191,139 @@ export default function CreateProfile({ userId }: { userId: any }) {
</Stack>
</Box>
<TextInput
label="Nama"
onChange={(val) => {
setValue({
...value,
name: val.target.value,
});
}}
/>
<TextInput
label="Email"
onChange={(val) => {
setValue({
...value,
email: val.target.value,
});
}}
/>
<TextInput
label="Alamat"
onChange={(val) => {
setValue({
...value,
alamat: val.target.value,
});
}}
/>
<Select
label="Jenis Kelamin"
data={[
{ value: "Laki-laki", label: "Laki-laki" },
{ value: "Perempuan", label: "Perempuan" },
]}
onChange={(val) => {
setValue({
...value,
jenisKelamin: val as string,
});
}}
/>
<Button
mt={"md"}
radius={50}
bg={Warna.hijau_muda}
color="green"
onClick={() =>
onSubmit(router, value as any, userId, filePP as any, fileBG as any)
}
>
Simpan
</Button>
<Stack mb={"lg"}>
<TextInput
withAsterisk
label="Nama"
placeholder="Nama lengkap"
onChange={(val) => {
setValue({
...value,
name: val.target.value,
});
}}
/>
<TextInput
withAsterisk
icon={<IconAt size={15} />}
label="Email"
placeholder="Contoh: User@gmail.com"
error={
value.email.length > 0 && !value.email.includes("@")
? "Invalid email"
: ""
}
onChange={(val) => {
setValue({
...value,
email: val.target.value,
});
}}
/>
<TextInput
withAsterisk
label="Alamat"
placeholder="Alamat lengkap"
onChange={(val) => {
setValue({
...value,
alamat: val.target.value,
});
}}
/>
<Select
withAsterisk
label="Jenis Kelamin"
placeholder="Pilih satu"
data={[
{ value: "Laki-laki", label: "Laki-laki" },
{ value: "Perempuan", label: "Perempuan" },
]}
onChange={(val) => {
setValue({
...value,
jenisKelamin: val as string,
});
}}
/>
<ButtonAction
value={value as any}
userId={userId}
filePP={filePP as any}
fileBg={fileBG as any}
/>
</Stack>
</Stack>
</>
);
}
async function onSubmit(
router: AppRouterInstance,
value: MODEL_PROFILE,
userId: string,
filePP: FormData,
fileBg: FormData
) {
const body = {
userId: userId,
name: value.name,
email: value.email,
alamat: value.alamat,
jenisKelamin: value.jenisKelamin,
};
if(_.values(body).includes("")) return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data")
function ButtonAction({
value,
userId,
filePP,
fileBg,
}: {
value: MODEL_PROFILE;
userId: string;
filePP: FormData;
fileBg: FormData;
}) {
const router = useRouter();
const [loading, setLoading] = useState(false);
const gambarPP = new FormData();
gambarPP.append("filePP", filePP as any);
async function onSubmit() {
const body = {
userId: userId,
name: value.name,
email: value.email,
alamat: value.alamat,
jenisKelamin: value.jenisKelamin,
};
if (_.values(body).includes(""))
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data");
if (!body.email.includes("@"))
return ComponentGlobal_NotifikasiPeringatan("Invalid Email");
const gambarBG = new FormData();
gambarBG.append("fileBG", fileBg as any);
const gambarPP = new FormData();
gambarPP.append("filePP", filePP as any);
if(!gambarPP) return ComponentGlobal_NotifikasiPeringatan("Lengkapi foto profile")
if(!gambarBG) return ComponentGlobal_NotifikasiPeringatan("Lengkapi background profile")
await funCreateNewProfile(body as any, gambarPP, gambarBG).then((res) => {
if (res.status === 201) {
ComponentGlobal_NotifikasiBerhasil("Berhasil Membuat Profile")
router.push(RouterHome.main_home);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
const gambarBG = new FormData();
gambarBG.append("fileBG", fileBg as any);
if (!gambarPP)
return ComponentGlobal_NotifikasiPeringatan("Lengkapi foto profile");
if (!gambarBG)
return ComponentGlobal_NotifikasiPeringatan(
"Lengkapi background profile"
);
await funCreateNewProfile(body as any, gambarPP, gambarBG).then((res) => {
if (res.status === 201) {
setLoading(true);
ComponentGlobal_NotifikasiBerhasil("Berhasil Membuat Profile", 3000);
router.push(RouterHome.main_home);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}
return (
<>
<Button
loading={loading ? true : false}
loaderPosition="center"
mt={"md"}
radius={50}
bg={Warna.hijau_muda}
color="green"
onClick={() => {
onSubmit();
}}
>
Simpan
</Button>
</>
);
}

View File

@@ -23,15 +23,19 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
//Get data profile
const [dataProfile, setDataProfile] = useState(data);
const [loading, setLoading] = useState(false);
async function onUpdate() {
const body = dataProfile;
// console.log(body)
if (_.values(body).includes("")) return toast("Lengkapi data");
await Profile_funEditById(body).then((res) => {
if (res.status === 200) {
setLoading(true);
ComponentGlobal_NotifikasiBerhasil(res.message);
setTimeout(() => router.back(), 1000)
setTimeout(() => router.back(), 1000);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
@@ -47,18 +51,42 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
return (
<>
{/* <pre>{JSON.stringify(dataProfile, null, 2)}</pre> */}
<Stack px={"sm"}>
<TextInput
label="Username"
withAsterisk
label="Nomor"
disabled
value={dataProfile.User.username}
value={dataProfile?.User?.nomor}
/>
<TextInput label="Nomor" disabled value={dataProfile.User.nomor} />
<TextInput
withAsterisk
label="Username"
error={
data?.User?.username?.length < 5
? "Username minimal 5 karakter"
: ""
}
disabled
value={dataProfile?.User?.username}
onChange={(val) => {
// const dataUsername = _.clone(dataProfile)
setDataProfile({
...(dataProfile as any),
User: {
username: val.target.value,
},
});
}}
/>
<TextInput
withAsterisk
label="Nama"
placeholder="Nama"
value={dataProfile.name}
value={dataProfile?.name}
onChange={(val) => {
setDataProfile({
...dataProfile,
@@ -68,9 +96,15 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
/>
<TextInput
withAsterisk
label="Email"
placeholder="email"
value={dataProfile.email}
error={
dataProfile?.email?.length > 0 && !dataProfile?.email.includes("@")
? "Invalid email"
: ""
}
value={dataProfile?.email}
onChange={(val) => {
setDataProfile({
...dataProfile,
@@ -80,6 +114,7 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
/>
<TextInput
withAsterisk
label="Alamat"
placeholder="alamat"
value={dataProfile.alamat}
@@ -92,8 +127,9 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
/>
<Select
withAsterisk
label="Jenis Kelamin"
value={dataProfile.jenisKelamin}
value={dataProfile?.jenisKelamin}
data={[
{ value: "Laki-laki", label: "Laki-laki" },
{ value: "Perempuan", label: "Perempuan" },
@@ -101,7 +137,7 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
onChange={(val: any) => {
setDataProfile({
...dataProfile,
jenisKelamin: val
jenisKelamin: val,
});
}}
/>
@@ -111,6 +147,8 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
radius={50}
bg={Warna.biru}
color="cyan"
loading={loading ? true : false}
loaderPosition="center"
onClick={() => onUpdate()}
>
Update

View File

@@ -5,6 +5,17 @@ import { MODEL_PROFILE } from "../../model/interface";
import { revalidatePath } from "next/cache";
export async function Profile_funEditById(data: MODEL_PROFILE) {
// console.log(data);
const cekEmail = await prisma.profile.findUnique({
where: {
email: data.email,
},
});
if (cekEmail && cekEmail.id != data.id)
return { status: 400, message: "Email sudah digunakan" };
const updt = await prisma.profile.update({
where: {
id: data.id,

View File

@@ -6,35 +6,18 @@ import _ from "lodash";
import { v4 } from "uuid";
import { revalidatePath } from "next/cache";
export async function Profile_funUpdateBackground(profileId: string, file: FormData) {
const findProfile = await prisma.profile.findFirst({
where: {
id: profileId,
},
});
const findBackground = await prisma.imagesBackground.findFirst({
where: {
id: findProfile?.imagesBackgroundId as string,
},
select: {
url: true,
},
});
if (!findBackground) return { status: 400, message: "Foto tidak ditemukan" };
if (findBackground) fs.unlinkSync(`./public/profile/background/${findBackground.url}`);
export async function Profile_funUpdateBackground(
profileId: string,
file: FormData
) {
const gambarBackground: any = file.get("file");
const fileName = gambarBackground.name;
const fileExtension = _.lowerCase(gambarBackground.name.split(".").pop());
const randomName = v4(fileName) + "." + fileExtension;
const fRandomName = v4(fileName) + "." + fileExtension;
const uploadBG = await prisma.imagesBackground.update({
where: {
id: findProfile?.imagesBackgroundId as string,
},
const uploadBG = await prisma.imagesBackground.create({
data: {
url: randomName,
url: fRandomName,
label: "PROFILE_BACKGROUND",
},
select: {
@@ -43,13 +26,77 @@ export async function Profile_funUpdateBackground(profileId: string, file: FormD
},
});
if (!uploadBG) return { status: 400, message: "Gagal upload foto background" };
const uploadPP_Folder = Buffer.from(await gambarBackground.arrayBuffer());
fs.writeFileSync(`./public/profile/background/${uploadBG.url}`, uploadPP_Folder);
if (!uploadBG)
return { status: 400, message: "Gagal upload gambar background" };
const uploadBG_Folder = Buffer.from(await gambarBackground.arrayBuffer());
fs.writeFileSync(
`./public/profile/background/${uploadBG.url}`,
uploadBG_Folder
);
revalidatePath("/dev/katalog");
const updateBackground = await prisma.profile.update({
where: {
id: profileId,
},
data: {
imagesBackgroundId: uploadBG.id,
},
});
if (!updateBackground)
return { status: 400, message: "Gagal update gambar background" };
revalidatePath("/dev/katalog");
return {
status: 200,
message: "Update berhasil",
};
// const findProfile = await prisma.profile.findFirst({
// where: {
// id: profileId,
// },
// });
// const findBackground = await prisma.imagesBackground.findFirst({
// where: {
// id: findProfile?.imagesBackgroundId as string,
// },
// select: {
// url: true,
// },
// });
// if (!findBackground) return { status: 400, message: "Foto tidak ditemukan" };
// if (findBackground) fs.unlinkSync(`./public/profile/background/${findBackground.url}`);
// const gambarBackground: any = file.get("file");
// const fileName = gambarBackground.name;
// const fileExtension = _.lowerCase(gambarBackground.name.split(".").pop());
// const randomName = v4(fileName) + "." + fileExtension;
// const uploadBG = await prisma.imagesBackground.update({
// where: {
// id: findProfile?.imagesBackgroundId as string,
// },
// data: {
// url: randomName,
// label: "PROFILE_BACKGROUND",
// },
// select: {
// id: true,
// url: true,
// },
// });
// if (!uploadBG) return { status: 400, message: "Gagal upload foto background" };
// const uploadBG_Folder = Buffer.from(await gambarBackground.arrayBuffer());
// fs.writeFileSync(`./public/profile/background/${uploadBG.url}`, uploadBG_Folder);
// revalidatePath("/dev/katalog");
// return {
// status: 200,
// message: "Update berhasil",
// };
}

View File

@@ -7,34 +7,14 @@ import { v4 } from "uuid";
import { revalidatePath } from "next/cache";
export async function Profile_funUpdateFoto(profileId: string, file: FormData) {
const findProfile = await prisma.profile.findFirst({
where: {
id: profileId,
},
});
const findFoto = await prisma.images.findFirst({
where: {
id: findProfile?.imagesId as string,
},
select: {
url: true,
},
});
if (!findFoto) return { status: 400, message: "Foto tidak ditemukan" };
if (findFoto) fs.unlinkSync(`./public/profile/foto/${findFoto.url}`);
const gambarProfile: any = file.get("file");
const fileName = gambarProfile.name;
const fileExtension = _.lowerCase(gambarProfile.name.split(".").pop());
const randomName = v4(fileName) + "." + fileExtension;
const fRandomName = v4(fileName) + "." + fileExtension;
const uploadPP = await prisma.images.update({
where: {
id: findProfile?.imagesId as string,
},
const uploadPP = await prisma.images.create({
data: {
url: randomName,
url: fRandomName,
label: "PROFILE_FOTO",
},
select: {
@@ -46,10 +26,69 @@ export async function Profile_funUpdateFoto(profileId: string, file: FormData) {
if (!uploadPP) return { status: 400, message: "Gagal upload foto profile" };
const uploadPP_Folder = Buffer.from(await gambarProfile.arrayBuffer());
fs.writeFileSync(`./public/profile/foto/${uploadPP.url}`, uploadPP_Folder);
const updateProfile = await prisma.profile.update({
where: {
id: profileId,
},
data: {
imagesId: uploadPP.id,
},
});
if (!updateProfile) return { status: 400, message: "Gagal update foto" };
revalidatePath("/dev/katalog");
return {
status: 200,
message: "Update berhasil",
};
// const findProfile = await prisma.profile.findFirst({
// where: {
// id: profileId,
// },
// });
// const findFoto = await prisma.images.findFirst({
// where: {
// id: findProfile?.imagesId as string,
// },
// select: {
// url: true,
// },
// });
// if (!findFoto) return { status: 400, message: "Foto tidak ditemukan" };
// if (findFoto) fs.unlinkSync(`./public/profile/foto/${findFoto.url}`);
// const gambarProfile: any = file.get("file");
// const fileName = gambarProfile.name;
// const fileExtension = _.lowerCase(gambarProfile.name.split(".").pop());
// const randomName = v4(fileName) + "." + fileExtension;
// const uploadPP = await prisma.images.update({
// where: {
// id: findProfile?.imagesId as string,
// },
// data: {
// url: randomName,
// label: "PROFILE_FOTO",
// },
// select: {
// id: true,
// url: true,
// },
// });
// if (!uploadPP) return { status: 400, message: "Gagal upload foto profile" };
// const uploadPP_Folder = Buffer.from(await gambarProfile.arrayBuffer());
// fs.writeFileSync(`./public/profile/foto/${uploadPP.url}`, uploadPP_Folder);
// revalidatePath("/dev/katalog");
// return {
// status: 200,
// message: "Update berhasil",
// };
}

View File

@@ -2,7 +2,7 @@ import ProfileLayout from "./create/layout";
import CreateProfile from "./create/view";
import EditProfileLayout from "./edit/layout";
import EditProfileView from "./edit/view";
import UploadFotoProfile from "./upload/foto_profile/view";
import UploadFotoProfile from "./upload/foto_profile";
import UploadFotoProfileLayout from "./upload/foto_profile/layout"
import ProfileView from "./main/view";
import Profile_UpdateFotoBackground from "./upload/foto_background";

View File

@@ -40,6 +40,10 @@ export default function ProfileView({
userLoginId: string;
}) {
const router = useRouter();
const [loadingPP, setLoadingPP] = useState(false);
const [loadingBG, setLoadingBG] = useState(false);
const [loadingEdit, setLoadingEdit] = useState(false);
// const [data, setData] = useState(profile);
// useShallowEffect(() => {
// funGetUserProfile(user.id ?? "").then(setProfile as any);
@@ -49,7 +53,7 @@ export default function ProfileView({
return (
<>
{/* <pre>{JSON.stringify(profile, null,2)}</pre> */}
<Paper p={"sm"} bg={"gray.1"} shadow="lg" withBorder>
<Paper px={"md"} py={"sm"} bg={"gray.1"} shadow="lg" withBorder>
{/* Background dan foto */}
{/* Upload Background Profile */}
@@ -57,12 +61,14 @@ export default function ProfileView({
<AspectRatio ratio={16 / 9}>
<Paper radius={"sm"} shadow="md">
<Image
radius={"sm"}
height={210}
alt=""
mah={"100%"}
maw={"100%"}
alt="Background"
src={
RouterProfile.api_url_background +
`${profile?.ImagesBackground.url}`
profile?.ImagesBackground.url
? RouterProfile.api_url_background +
`${profile?.ImagesBackground.url}`
: "/aset/no-image.png"
}
/>
</Paper>
@@ -72,19 +78,21 @@ export default function ProfileView({
{profile?.User.id === userLoginId ? (
<Center>
<ActionIcon
ml={{base: 300, sm: 500, md: 900, lg: 1000}}
loading={loadingBG ? true : false}
ml={{ base: 300, sm: 500, md: 900, lg: 1000 }}
mt={-10}
bg={"gray.5"}
variant="transparent"
radius={50}
onClick={() =>
onClick={() => {
setLoadingBG(true);
router.push(
RouterProfile.update_foto_background + `${profile.id}`
)
}
);
}}
sx={{
position: "relative",
// zIndex: 2,
color: "gray",
border: "1px",
borderStyle: "solid",
}}
@@ -110,10 +118,15 @@ export default function ProfileView({
bg={"gray.2"}
sx={{
borderStyle: "solid",
borderColor: "black",
borderWidth: "1px",
borderColor: "gray",
borderWidth: "0.5px",
}}
src={RouterProfile.api_url_foto + `${profile?.ImageProfile.url}`}
src={
profile?.ImageProfile?.url
? RouterProfile.api_url_foto +
`${profile?.ImageProfile.url}`
: "/aset/global/avatar.png"
}
size={100}
radius={"100%"}
/>
@@ -124,16 +137,18 @@ export default function ProfileView({
{profile?.User.id === userLoginId ? (
<Center>
<ActionIcon
loading={loadingPP ? true : false}
mr={-70}
mt={15}
variant="transparent"
bg={"gray.5"}
radius={50}
onClick={() =>
onClick={() => {
setLoadingPP(true);
router.push(
RouterProfile.update_foto_profile + `${profile.id}`
)
}
);
}}
sx={{
position: "relative",
border: "1px",
@@ -150,30 +165,47 @@ export default function ProfileView({
{/* Username dan Nama */}
<Group position="apart" pt={profile?.User.id === userLoginId ? 0 : "xl" }>
<Flex direction={"column"} mt={"lg"}>
<Text fz={"lg"} fw={"bold"}>
{profile?.name}
</Text>
<Text fz={"xs"}>@{profile?.User?.username}</Text>
</Flex>
{profile?.User.id === userLoginId ? (
<ActionIcon
variant="transparent"
onClick={() => {
router.push(RouterProfile.edit + `${profile.id}`);
}}
>
<IconEditCircle color={Warna.hijau_muda} />
</ActionIcon>
) : (
""
)}
</Group>
<Grid>
<Grid.Col
span={"auto"}
pt={profile?.User.id === userLoginId ? 10 : 50}
>
<Stack spacing={0}>
<Text fz={"lg"} fw={"bold"} lineClamp={1}>
{profile?.name}
</Text>
<Text fz={"xs"} c={"dark.3"}>
@{profile?.User?.username}
</Text>
</Stack>
</Grid.Col>
<Grid.Col span={"content"}>
{profile?.User.id === userLoginId ? (
<ActionIcon
loading={loadingEdit ? true : false}
variant="transparent"
onClick={() => {
setLoadingEdit(true);
router.push(RouterProfile.edit + `${profile.id}`);
}}
>
<IconEditCircle color={Warna.hijau_muda} />
</ActionIcon>
) : (
""
)}
</Grid.Col>
</Grid>
{/* <Group
position="apart"
pt={profile?.User.id === userLoginId ? 0 : "xl"}
>
<Flex direction={"column"} mt={"lg"}></Flex>
</Group> */}
{/* Info user: nomor, email dll */}
<Stack spacing={"xs"} pt={"lg"}>
<Stack spacing={"xs"} pt={"lg"}>
<Grid>
<Grid.Col span={"content"}>
<IconAddressBook />

View File

@@ -33,6 +33,7 @@ export default function Profile_UpdateFotoBackground({
const [profile, setProfile] = useState(dataProfile);
const [file, setFile] = useState<File | null>(null);
const [image, setImage] = useState<any | null>(null);
const [loading, setLoading] = useState(false);
return (
<>
@@ -57,10 +58,15 @@ export default function Profile_UpdateFotoBackground({
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
// console.log(buffer, "ini buffer");
// console.log(files, " ini file");
setImage(buffer);
setFile(files);
if (files.size > 1000000) {
ComponentGlobal_NotifikasiPeringatan(
"Maaf, Ukuran file terlalu besar, maximum 1mb",
3000
);
} else {
setImage(buffer);
setFile(files);
}
} catch (error) {
console.log(error);
}
@@ -85,10 +91,13 @@ export default function Profile_UpdateFotoBackground({
</Paper>
<Button
disabled={file ? false : true}
loading={loading ? true : false}
loaderPosition="center"
radius={"xl"}
onClick={() => onUpdate(router, profile.id, file as any)}
onClick={() => onUpdate(router, profile.id, file as any, setLoading)}
>
Simpan
Update
</Button>
</Stack>
</>
@@ -98,13 +107,15 @@ export default function Profile_UpdateFotoBackground({
async function onUpdate(
router: AppRouterInstance,
profileId: string,
file: FormData
file: FormData,
setLoading: any
) {
const gambar = new FormData();
gambar.append("file", file as any);
await Profile_funUpdateBackground(profileId, gambar).then((res) => {
if (res.status === 200) {
setLoading(true);
ComponentGlobal_NotifikasiBerhasil(res.message);
router.back();
} else {

View File

@@ -19,6 +19,7 @@ import { useRouter } from "next/navigation";
import { Profile_funUpdateFoto } from "../../fun/update/fun_update_foto_profile";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/component_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/component_global/notif_global/notifikasi_peringatan";
export default function UploadFotoProfile({
dataProfile,
@@ -29,6 +30,7 @@ export default function UploadFotoProfile({
const [profile, setProfile] = useState(dataProfile);
const [file, setFile] = useState<File | null>(null);
const [image, setImage] = useState<any | null>(null);
const [loading, setLoading] = useState(false);
return (
<>
@@ -52,10 +54,15 @@ export default function UploadFotoProfile({
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
// console.log(buffer, "ini buffer");
// console.log(files, " ini file");
setImage(buffer);
setFile(files);
if (files.size > 1000000) {
ComponentGlobal_NotifikasiPeringatan(
"Maaf, Ukuran file terlalu besar, maximum 1mb",
3000
);
} else {
setImage(buffer);
setFile(files);
}
} catch (error) {
console.log(error);
}
@@ -80,10 +87,15 @@ export default function UploadFotoProfile({
</Paper>
<Button
disabled={file ? false : true}
loading={loading ? true : false}
loaderPosition="center"
radius={"xl"}
onClick={() => onUpdate(router, profile.id, file as any)}
onClick={() => {
onUpdate(router, profile.id, file as any, setLoading);
}}
>
Simpan
Update
</Button>
</Stack>
</>
@@ -93,13 +105,15 @@ export default function UploadFotoProfile({
async function onUpdate(
router: AppRouterInstance,
profileId: string,
file: FormData
file: FormData,
setLoading: any
) {
const gambar = new FormData();
gambar.append("file", file as any);
await Profile_funUpdateFoto(profileId, gambar).then((res) => {
if (res.status === 200) {
setLoading(true);
ComponentGlobal_NotifikasiBerhasil(res.message);
router.back();
} else {

View File

@@ -20,6 +20,7 @@ import { useState } from "react";
import { UserSearch_searchByName } from "../fun/search/fun_search_by_name";
import { useRouter } from "next/navigation";
import ComponentGlobal_MaintenanceInformation from "@/app_modules/component_global/maintenance_information";
import ComponentGlobal_V2_LoadingPage from "@/app_modules/component_global/loading_page_v2";
export default function UserSearch_MainView({
listUser,
@@ -28,6 +29,7 @@ export default function UserSearch_MainView({
}) {
const router = useRouter();
const [user, setUser] = useState(listUser);
const [loading, setLoading] = useState(false);
async function onSearch(name: string) {
await UserSearch_searchByName(name).then((res) => setUser(res as any));
@@ -41,6 +43,8 @@ export default function UserSearch_MainView({
// </>
// );
if(loading) return <ComponentGlobal_V2_LoadingPage/>
return (
<>
<Box>
@@ -60,11 +64,11 @@ export default function UserSearch_MainView({
""
) : (
<Stack key={e.id} spacing={"xs"} mt={"xs"}>
<Grid >
<Grid>
<Grid.Col span={2}>
<Center h={"100%"}>
<Avatar
sx={{borderStyle: "solid", borderWidth: "0.5px"}}
sx={{ borderStyle: "solid", borderWidth: "0.5px" }}
radius={"xl"}
size={"md"}
src={
@@ -76,7 +80,7 @@ export default function UserSearch_MainView({
</Grid.Col>
<Grid.Col span={"auto"}>
<Stack spacing={0}>
<Text fw={"bold"} truncate>
<Text fw={"bold"} lineClamp={1}>
{e?.Profile?.name}
</Text>
<Text fz={"sm"} fs={"italic"}>
@@ -88,11 +92,12 @@ export default function UserSearch_MainView({
<Center h={"100%"}>
<ActionIcon
variant="transparent"
onClick={() =>
onClick={() => {
setLoading(true);
router.push(
RouterProfile.katalog + `${e?.Profile?.id}`
)
}
);
}}
>
<IconChevronRight />
</ActionIcon>

View File

@@ -322,6 +322,14 @@
dependencies:
react-dropzone-esm "15.0.1"
"@mantine/form@^7.6.1":
version "7.6.1"
resolved "https://registry.yarnpkg.com/@mantine/form/-/form-7.6.1.tgz#b98307c91ae8fe5559590d2eefe6c60c22868330"
integrity sha512-S0pdvFohRX3ahzhrCGM+d2sBaSHH88UkQhbzyOAGJ7xqNjPJ11Bh/xb4Mc+NXXxaq9MjPrRVe6fgpKJtXszBpQ==
dependencies:
fast-deep-equal "^3.1.3"
klona "^2.0.6"
"@mantine/hooks@^6.0.17":
version "6.0.21"
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.21.tgz#bc009d8380ad18455b90f3ddaf484de16a13da95"
@@ -2940,6 +2948,11 @@ keyv@^4.5.3:
dependencies:
json-buffer "3.0.1"
klona@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==
language-subtag-registry@^0.3.20:
version "0.3.22"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"