Portofolio

#feat
- Create porto
- Edit Porto
- Upload gambar background profile
- List user
- Search user
## No issuue
This commit is contained in:
2024-01-19 14:16:16 +08:00
parent 01da30bdb5
commit 5f4337333a
175 changed files with 3451 additions and 1017 deletions

View File

@@ -1,16 +0,0 @@
"use server";
import { myConsole } from "@/app/fun/my_console";
import prisma from "@/app/lib/prisma";
export async function getFotoProfile(id: any) {
const imgUrl = await prisma.images.findUnique({
where: {
id: id,
},
select: {
id: true,
url: true,
},
});
return imgUrl;
}

View File

@@ -1,38 +0,0 @@
"use server";
import { myConsole } from "@/app/fun/my_console";
import prisma from "@/app/lib/prisma";
import { getToken } from "@/app_modules/home";
import { NextResponse } from "next/server";
/**
* @function api get data profile by user id
* @returns data profile
*/
export async function getProfile() {
const token = await getToken();
const dataProfile = await prisma.profile.findUnique({
where: {
userId: token.id,
},
select: {
id: true,
name: true,
email: true,
alamat: true,
jenisKelamin: true,
active: true,
imagesId: true,
User: {
select : {
username: true,
nomor: true
}
}
},
});
return dataProfile;
}

View File

@@ -18,7 +18,7 @@ export default function ProfileLayout({ children }: { children: any }) {
<AppShell
header={
<Header height={50} px={"sm"}>
<Header height={50} px={"sm"} sx={{borderBlockStyle: "none"}}>
<Group position="apart" h={50}>
<ActionIcon variant="transparent" onClick={() => router.push("/dev/home")}>
<IconArrowLeft />

View File

@@ -3,17 +3,40 @@
import { myConsole } from "@/app/fun/my_console";
import { ApiHipmi } from "@/app/lib/api";
import { Warna } from "@/app/lib/warna";
import { gs_token } from "@/app_modules/home/state/global_state";
import { Button, Select, Stack, TextInput } from "@mantine/core";
import {
AspectRatio,
Avatar,
Box,
Button,
Center,
FileButton,
Image,
Paper,
Select,
Stack,
TextInput,
} from "@mantine/core";
import { useAtom } from "jotai";
import _ from "lodash";
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 ComponentKatalog_NotedBox from "../../component/noted_box";
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
import { MODEL_PROFILE } from "../model/interface";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/component_global/notif_global/notifikasi_peringatan";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/component_global/notif_global/notifikasi_berhasil";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
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);
const [imgBG, setImgBG] = useState<any | null>();
const [value, setValue] = useState({
name: "",
@@ -22,33 +45,108 @@ export default function CreateProfile({ userId }: { userId: any }) {
jenisKelamin: "",
});
async function onSubmit() {
const body = {
userId: userId,
name: value.name,
email: value.email,
alamat: value.alamat,
jenisKelamin: value.jenisKelamin,
};
myConsole(body);
if (_.values(value).includes("")) return toast("Lengkapi data");
// if(_.values(value.email).includes(`${/^\S+@\S+$/.test(value.email) ? null : "Invalid email"}`)){}
await funCreateNewProfile(body).then((res) => {
if (res.status === 201) {
toast("Data tersimpan");
return router.push(`/dev/katalog/${userId}`);
} else {
toast("Gagal")
}
});
}
return (
<>
<Stack px={"sm"}>
<Stack px={"sm"} spacing={"xl"}>
<Box>
<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%"}
/>
</Center>
<Center>
<FileButton
onChange={async (files: any | null) => {
try {
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
// console.log(buffer, "ini buffer");
// console.log(files, " ini file");
setImgPP(buffer);
setFilePP(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
variant="outline"
w={150}
leftIcon={<IconCamera />}
compact
>
Upload
</Button>
)}
</FileButton>
</Center>
</Stack>
</Box>
<Box>
<Stack>
<ComponentKatalog_NotedBox informasi="Upload foto latar belakang profile anda." />
<AspectRatio ratio={16 / 9}>
<Paper
radius={"md"}
sx={{
borderStyle: "solid",
borderColor: "black",
borderWidth: "1px",
}}
>
<Image alt="Foto" src={imgBG ? imgBG : "/aset/no-img.png"} />
</Paper>
</AspectRatio>
<Center>
<FileButton
onChange={async (files: any | null) => {
try {
const buffer = URL.createObjectURL(
new Blob([new Uint8Array(await files.arrayBuffer())])
);
// console.log(buffer, "ini buffer");
// console.log(files, " ini file");
setImgBG(buffer);
setFileBG(files);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
variant="outline"
w={150}
leftIcon={<IconCamera />}
compact
>
Upload
</Button>
)}
</FileButton>
</Center>
</Stack>
</Box>
<TextInput
label="Nama"
onChange={(val) => {
@@ -94,7 +192,9 @@ export default function CreateProfile({ userId }: { userId: any }) {
radius={50}
bg={Warna.hijau_muda}
color="green"
onClick={() => onSubmit()}
onClick={() =>
onSubmit(router, value as any, userId, filePP as any, fileBG as any)
}
>
Simpan
</Button>
@@ -102,3 +202,41 @@ export default function CreateProfile({ userId }: { userId: any }) {
</>
);
}
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")
const gambarPP = new FormData();
gambarPP.append("filePP", filePP as any);
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) {
ComponentGlobal_NotifikasiBerhasil("Berhasil Membuat Profile")
router.push(RouterProfile.katalog + `${userId}`);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}

View File

@@ -10,24 +10,20 @@ import {
} from "@mantine/core";
import { IconArrowLeft } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import ComponentKatalog_HeaderTamplate from "../../component/header_tamplate";
export default function EditProfileLayout({ children, profileId }: { children: any, profileId: any }) {
const router = useRouter()
export default function EditProfileLayout({
children,
profileId,
}: {
children: any;
profileId: any;
}) {
const router = useRouter();
return (
<>
<AppShell
header={
<Header height={50} px={"sm"}>
<Group position="apart" h={50}>
<ActionIcon variant="transparent" onClick={() => router.push(`/dev/katalog/${profileId}`)}>
<IconArrowLeft />
</ActionIcon>
<Text>Edit Profile</Text>
<ActionIcon variant="transparent"></ActionIcon>
</Group>
</Header>
}
header={<ComponentKatalog_HeaderTamplate title="Edit Profile" />}
>
{children}
</AppShell>

View File

@@ -3,7 +3,6 @@
import { myConsole } from "@/app/fun/my_console";
import { ApiHipmi } from "@/app/lib/api";
import { Warna } from "@/app/lib/warna";
import { gs_token } from "@/app_modules/home/state/global_state";
import { Button, Loader, Select, Stack, TextInput } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useAtom } from "jotai";
@@ -11,12 +10,15 @@ import _ from "lodash";
import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-simple-toasts";
import { gs_profile } from "../state/global_state";
import { loadDataProfile } from "../fun/fun_get_profile";
import { MODEL_User_profile } from "@/app_modules/home/models/user_profile";
import funEditProfile from "../fun/fun_edit_profile";
export default function EditProfile({ data }: { data: MODEL_User_profile }) {
import funEditProfile from "../fun/fun_edit_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 { MODEL_PROFILE } from "../model/interface";
import { Profile_funEditById } from "../fun/update/fun_edit_profile_by_id";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
const router = useRouter();
//Get data profile
@@ -26,12 +28,12 @@ export default function EditProfile({ data }: { data: MODEL_User_profile }) {
const body = dataProfile;
if (_.values(body).includes("")) return toast("Lengkapi data");
await funEditProfile(body).then((res) => {
await Profile_funEditById(body).then((res) => {
if (res.status === 200) {
toast("Update berhasil");
setTimeout(() => router.push(`/dev/katalog/${data.Profile?.id}`), 1000);
ComponentGlobal_NotifikasiBerhasil(res.message);
setTimeout(() => router.back(), 1000)
} else {
toast("Gagal update");
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}
@@ -46,20 +48,21 @@ export default function EditProfile({ data }: { data: MODEL_User_profile }) {
return (
<>
<Stack px={"sm"}>
<TextInput label="Username" disabled value={dataProfile.username} />
<TextInput label="Nomor" disabled value={dataProfile.nomor} />
<TextInput
label="Username"
disabled
value={dataProfile.User.username}
/>
<TextInput label="Nomor" disabled value={dataProfile.User.nomor} />
<TextInput
label="Nama"
placeholder="username"
value={dataProfile.Profile?.name}
placeholder="Nama"
value={dataProfile.name}
onChange={(val) => {
setDataProfile({
...(dataProfile as any),
Profile: {
...dataProfile.Profile,
name: val.target.value,
},
...dataProfile,
name: val.target.value,
});
}}
/>
@@ -67,14 +70,11 @@ export default function EditProfile({ data }: { data: MODEL_User_profile }) {
<TextInput
label="Email"
placeholder="email"
value={dataProfile.Profile?.email}
value={dataProfile.email}
onChange={(val) => {
setDataProfile({
...(dataProfile as any),
Profile: {
...dataProfile.Profile,
email: val.target.value,
},
...dataProfile,
email: val.target.value,
});
}}
/>
@@ -82,32 +82,26 @@ export default function EditProfile({ data }: { data: MODEL_User_profile }) {
<TextInput
label="Alamat"
placeholder="alamat"
value={dataProfile.Profile?.alamat}
value={dataProfile.alamat}
onChange={(val) => {
setDataProfile({
...(dataProfile as any),
Profile: {
...dataProfile.Profile,
alamat: val.target.value,
},
...dataProfile,
alamat: val.target.value,
});
}}
/>
<Select
label="Jenis Kelamin"
value={dataProfile.Profile?.jenisKelamin}
value={dataProfile.jenisKelamin}
data={[
{ value: "Laki-laki", label: "Laki-laki" },
{ value: "Perempuan", label: "Perempuan" },
]}
onChange={(val) => {
onChange={(val: any) => {
setDataProfile({
...(dataProfile as any),
Profile: {
...dataProfile.Profile,
jenisKelamin: val,
},
...dataProfile,
jenisKelamin: val
});
}}
/>

View File

@@ -1,25 +1,88 @@
"use server";
import prisma from "@/app/lib/prisma";
import { MODEL_PROFILE } from "../model/interface";
import _ from "lodash";
import { v4 } from "uuid";
import fs from "fs";
export default async function funCreateNewProfile(data: any) {
// console.log(data);
const body = data;
export default async function funCreateNewProfile(
req: MODEL_PROFILE,
gambarPP: FormData,
gambarBG: FormData
) {
const body = req;
const res = await prisma.profile.create({
const findEmail = await prisma.profile.findUnique({
where: {
email: body.email,
},
});
if (findEmail) return { status: 400, message: "Email telah digunakan" };
const gambarProfile: any = gambarPP.get("filePP");
const fileName = gambarProfile.name;
const fileExtension = _.lowerCase(gambarProfile.name.split(".").pop());
const fRandomName = v4(fileName) + "." + fileExtension;
const uploadPP = await prisma.images.create({
data: {
url: fRandomName,
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);
const gambarBackground: any = gambarBG.get("fileBG");
const fileNameBG = gambarBackground.name;
const fileExtensionBG = _.lowerCase(gambarBackground.name.split(".").pop());
const fRandomNameBG = v4(fileNameBG) + "." + fileExtensionBG;
const uploadBG = await prisma.imagesBackground.create({
data: {
url: fRandomNameBG,
label: "PROFILE_BACKGROUND",
},
select: {
id: true,
url: true,
},
});
if (!uploadBG)
return { status: 400, message: "Gagal upload background profile" };
const uploadBG_Folder = Buffer.from(await gambarBackground.arrayBuffer());
fs.writeFileSync(
`./public/profile/background/${uploadBG.url}`,
uploadBG_Folder
);
const createProfile = await prisma.profile.create({
data: {
userId: body.userId,
name: body.name,
email: body.email,
alamat: body.alamat,
jenisKelamin: body.jenisKelamin,
imagesId: uploadPP.id,
imagesBackgroundId: uploadBG.id,
},
});
if (!res) return { status: 400 };
if (!createProfile) return { status: 400, message: "Gagal membuat profile" };
return {
status: 201,
success: true,
message: "Berhasil",
};
}

View File

@@ -1,9 +1,17 @@
"use server";
import prisma from "@/app/lib/prisma";
import { MODEL_User_profile } from "@/app_modules/home/models/user_profile";
import { MODEL_PROFILE_OLD } from "@/app_modules/home/model/user_profile";
export default async function funEditProfile(data: MODEL_PROFILE_OLD) {
// const cekEmail = await prisma.profile.findMany({
// where: {
// email: data.Profile.email
// }
// })
// if(cekEmail) return {status: 400, message: "Email sudah di gunakan"}
export default async function funEditProfile(data: MODEL_User_profile) {
const res = await prisma.profile.update({
where: {
id: data.Profile?.id,
@@ -16,10 +24,10 @@ export default async function funEditProfile(data: MODEL_User_profile) {
},
});
if (!res) return { status: 400 };
if (!res) return { status: 400, message: "Gagal update" };
return {
status: 200,
success: true,
message: "Berhasil update",
};
}

View File

@@ -1,15 +0,0 @@
import { myConsole } from "@/app/fun/my_console";
import { getProfile } from "..";
/**
* @function get data profile
* @param setProfile
* @returns data profile
*/
export async function loadDataProfile(setProfile: any) {
await getProfile()
.then((res) => res)
.then((val) => {
setProfile(val);
});
}

View File

@@ -0,0 +1,14 @@
"use server";
import prisma from "@/app/lib/prisma";
export async function Profile_getOneById(profileId: string) {
const data = await prisma.profile.findFirst({
where: {
id: profileId,
},
});
return data;
}

View File

@@ -0,0 +1,29 @@
"use server";
import prisma from "@/app/lib/prisma";
export async function Profile_getOneProfileAndUserById(profileId: string) {
const data = await prisma.profile.findFirst({
where: {
id: profileId,
},
select: {
userId: true,
User: true,
id: true,
name: true,
email: true,
alamat: true,
jenisKelamin: true,
imagesId: true,
imagesBackgroundId: true,
ImageProfile: true,
ImagesBackground: true
}
});
// console.log(data)
return data;
}

View File

@@ -0,0 +1,26 @@
"use server";
import prisma from "@/app/lib/prisma";
import { MODEL_PROFILE } from "../../model/interface";
import { revalidatePath } from "next/cache";
export async function Profile_funEditById(data: MODEL_PROFILE) {
const updt = await prisma.profile.update({
where: {
id: data.id,
},
data: {
name: data.name,
email: data.email,
alamat: data.alamat,
jenisKelamin: data.jenisKelamin,
},
});
if(!updt) return {status: 400, message: "Gagal update"}
revalidatePath("/dev/katalog")
return {
status: 200,
message: "Berhasil update"
}
}

View File

@@ -0,0 +1,55 @@
"use server";
import fs from "fs";
import prisma from "@/app/lib/prisma";
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}`);
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 uploadPP_Folder = Buffer.from(await gambarBackground.arrayBuffer());
fs.writeFileSync(`./public/profile/background/${uploadBG.url}`, uploadPP_Folder);
revalidatePath("/dev/katalog");
return {
status: 200,
message: "Update berhasil",
};
}

View File

@@ -0,0 +1,55 @@
"use server";
import fs from "fs";
import prisma from "@/app/lib/prisma";
import _ from "lodash";
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 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

@@ -1,16 +1,16 @@
import ProfileLayout from "./create/layout";
import CreateProfile from "./create/view";
import { getProfile } from "./api/get-profile";
import EditProfileLayout from "./edit/layout";
import EditProfileView from "./edit/view";
import UploadFotoProfile from "./upload/view";
import UploadFotoProfileLayout from "./upload/layout"
import UploadFotoProfile from "./upload/foto_profile/view";
import UploadFotoProfileLayout from "./upload/foto_profile/layout"
import ProfileView from "./main/view";
import Profile_UpdateFotoBackground from "./upload/foto_background";
import LayoutProfile_UpdateFotoBackground from "./upload/foto_background/layout";
export {
ProfileLayout,
CreateProfile,
getProfile,
EditProfileView,
EditProfileLayout,
UploadFotoProfile,

View File

@@ -3,6 +3,8 @@
import { Warna } from "@/app/lib/warna";
import {
ActionIcon,
AspectRatio,
Avatar,
BackgroundImage,
Box,
Center,
@@ -25,158 +27,207 @@ import {
} from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { myConsole } from "@/app/fun/my_console";
import { useAtom } from "jotai";
import { ApiHipmi } from "@/app/lib/api";
import { loadDataProfile } from "../fun/fun_get_profile";
import { getFotoProfile } from "../api/get-foto-profile";
import { gs_fotoProfile, gs_profile } from "../state/global_state";
import { getProfile } from "..";
import { MODEL_User_profile } from "@/app_modules/home/models/user_profile";
import { funGetUserProfile } from "@/app_modules/fun/get_user_profile";
import { MODEL_PROFILE_OLD } from "@/app_modules/home/model/user_profile";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import { MODEL_PROFILE } from "../model/interface";
export default function ProfileView({ user }: { user: MODEL_User_profile }) {
export default function ProfileView({
profile,
userLoginId,
}: {
profile: MODEL_PROFILE;
userLoginId: string;
}) {
const router = useRouter();
const [stateUser, setStateUser] = useState(user);
useShallowEffect(() => {
funGetUserProfile(user.id ?? "").then(setStateUser as any);
}, []);
// const [data, setData] = useState(profile);
// useShallowEffect(() => {
// funGetUserProfile(user.id ?? "").then(setProfile as any);
// }, []);
if (!stateUser) return <></>;
// if (!profile) return <></>;
return (
<>
{/* Background dan foto */}
<Box>
<Paper bg={"gray"} p={"md"}>
<Image alt="" src={"/aset/logo.png"} />
</Paper>
<Center>
<Paper
radius={100}
h={105}
w={105}
sx={{
borderStyle: "solid",
borderRadius: "100%",
borderWidth: 2,
marginBottom: 10,
paddingBottom: 10,
position: "absolute",
zIndex: 0,
}}
>
<Center h={101}>
{stateUser.Profile?.ImageProfile?.url && (
<Image
src={ApiHipmi.get_foto + stateUser.Profile?.ImageProfile?.url}
alt=""
radius={100}
width={100}
height={100}
/>
)}
{/* <pre>{JSON.stringify(profile, null,2)}</pre> */}
<Paper p={"sm"} bg={"gray.1"} shadow="lg" withBorder>
{/* Background dan foto */}
<Box>
<AspectRatio ratio={16 / 9}>
<Paper radius={"sm"} shadow="md">
<Image
radius={"sm"}
height={210}
alt=""
src={
RouterProfile.api_url_background +
`${profile.ImagesBackground.url}`
}
/>
</Paper>
</AspectRatio>
{profile.User.id === userLoginId ? (
<ActionIcon
ml={325}
mt={-10}
bg={"gray.5"}
variant="transparent"
radius={50}
onClick={() =>
router.push(
RouterProfile.update_foto_background + `${profile.id}`
)
}
sx={{
position: "absolute",
zIndex: 2,
border: "1px",
borderStyle: "solid",
}}
>
<IconCamera color="black" size={20} />
</ActionIcon>
) : (
""
)}
<Center>
<Box
sx={{
marginBottom: 10,
paddingBottom: 10,
position: "absolute",
zIndex: 0,
}}
>
<Avatar
bg={"gray.2"}
sx={{
borderStyle: "solid",
borderColor: "black",
borderWidth: "1px",
}}
src={RouterProfile.api_url_foto + `${profile.ImageProfile.url}`}
size={100}
radius={"100%"}
/>
</Box>
</Center>
{profile.User.id === userLoginId ? (
<Center>
<ActionIcon
mr={-70}
mt={15}
variant="transparent"
bg={"gray.5"}
radius={50}
onClick={() =>
router.push(
RouterProfile.update_foto_profile + `${profile.id}`
)
}
sx={{
position: "relative",
border: "1px",
borderStyle: "solid",
}}
>
<IconCamera color="black" size={20} />
</ActionIcon>
</Center>
</Paper>
</Center>
) : (
""
)}
</Box>
<Center>
<ActionIcon
mr={-70}
mt={15}
variant="transparent"
bg={"gray"}
radius={50}
onClick={() => router.push(`/dev/profile/upload/${stateUser.Profile?.id}`)}
sx={{ position: "relative" }}
>
<IconCamera color="black" size={20} />
</ActionIcon>
</Center>
</Box>
{/* Username dan Nama */}
{/* Username dan Nama */}
<Group position="apart">
<Flex direction={"column"} mt={"lg"}>
<Text fz={"lg"} fw={"bold"}>
{stateUser.Profile?.name}
</Text>
<Text fz={"xs"}>@{stateUser.username}</Text>
<Group position="apart">
<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>
{/* Info user: nomor, email dll */}
<Flex direction={"column"} pt={"lg"}>
<Grid>
<Grid.Col span={"content"}>
<IconAddressBook />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{" "}
<Text>+{profile.User.nomor}</Text>
</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={"content"}>
<IconMail />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{" "}
<Text> {profile.email}</Text>
</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={"content"}>
<IconHome />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text> {profile.alamat}</Text>
</Grid.Col>
</Grid>
{(() => {
if (profile.jenisKelamin === "Laki - laki") {
return (
<>
<Grid>
<Grid.Col span={"content"}>
<IconGenderMale />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text> {profile.jenisKelamin}</Text>
</Grid.Col>
</Grid>
</>
);
} else {
return (
<>
<Grid>
<Grid.Col span={"content"}>
<IconGenderFemale />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text> {profile.jenisKelamin}</Text>
</Grid.Col>
</Grid>
</>
);
}
})()}
</Flex>
<ActionIcon
variant="transparent"
onClick={() => {
router.push(`/dev/profile/edit/${stateUser.id}`);
}}
>
<IconEditCircle color={Warna.hijau_muda} size={20} />
</ActionIcon>
</Group>
{/* Info user: nomor, email dll */}
<Flex direction={"column"} pt={"lg"}>
<Grid>
<Grid.Col span={"content"}>
<IconAddressBook />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{" "}
<Text>+{stateUser.nomor}</Text>
</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={"content"}>
<IconMail />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>
{" "}
<Text> {stateUser.Profile?.email}</Text>
</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={"content"}>
<IconHome />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text> {stateUser.Profile?.alamat}</Text>
</Grid.Col>
</Grid>
{(() => {
if (stateUser.Profile?.jenisKelamin === "Laki - laki") {
return (
<>
<Grid>
<Grid.Col span={"content"}>
<IconGenderMale />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text> {stateUser.Profile?.jenisKelamin}</Text>
</Grid.Col>
</Grid>
</>
);
} else {
return (
<>
<Grid>
<Grid.Col span={"content"}>
<IconGenderFemale />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text> {stateUser.Profile?.jenisKelamin}</Text>
</Grid.Col>
</Grid>
</>
);
}
})()}
</Flex>
</Paper>
{/* <pre>{JSON.stringify(profile, null, 2)}</pre> */}
</>

View File

@@ -0,0 +1,19 @@
import { MODEL_USER } from "@/app_modules/home/model/interface";
import { MODEL_IMAGES } from "@/app_modules/models/interface";
export interface MODEL_PROFILE {
userId: string;
User: MODEL_USER;
id: string;
name: string;
email: string;
alamat: string;
jenisKelamin: string;
active: string;
createdAt: Date;
updatedAt: Date;
ImageProfile: MODEL_IMAGES;
imagesId: string;
ImagesBackground: MODEL_IMAGES;
imagesBackgroundId: string;
}

View File

@@ -1,5 +1,4 @@
import { atomWithStorage } from "jotai/utils";
import { getProfile } from "..";
export const gs_profile = atomWithStorage<any | null>("gs_profile", null);
export const gs_fotoProfile = atomWithStorage<any | null>("gs_fotoProfile" , null)

View File

@@ -0,0 +1,114 @@
"use client";
import {
AspectRatio,
Button,
Center,
FileButton,
Image,
Paper,
Stack,
Title,
} from "@mantine/core";
import { useState } from "react";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import { MODEL_PROFILE } from "../../model/interface";
import { IconCamera } from "@tabler/icons-react";
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
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_NotifikasiPeringatan } from "@/app_modules/component_global/notif_global/notifikasi_peringatan";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
import { Profile_funUpdateBackground } from "../../fun/update/fun_update_background";
export default function Profile_UpdateFotoBackground({
dataProfile,
}: {
dataProfile: MODEL_PROFILE;
}) {
const router = useRouter();
const [profile, setProfile] = useState(dataProfile);
const [file, setFile] = useState<File | null>(null);
const [image, setImage] = useState<any | null>(null);
return (
<>
<Stack spacing={"xl"}>
<Paper p={"sm"} withBorder radius={"sm"} shadow="">
<Stack>
<AspectRatio ratio={16 / 9}>
<Image
alt="Foto"
src={
image
? image
: RouterProfile.api_background_profile +
profile.imagesBackgroundId
}
/>
</AspectRatio>
<Center>
<FileButton
onChange={async (files: any | null) => {
try {
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);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
variant="outline"
w={150}
leftIcon={<IconCamera />}
compact
>
Upload
</Button>
)}
</FileButton>
</Center>
</Stack>
</Paper>
<Button
radius={"xl"}
onClick={() => onUpdate(router, profile.id, file as any)}
>
Simpan
</Button>
</Stack>
</>
);
}
async function onUpdate(
router: AppRouterInstance,
profileId: string,
file: FormData
) {
const gambar = new FormData();
gambar.append("file", file as any);
await Profile_funUpdateBackground(profileId, gambar).then((res) => {
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message);
router.back();
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}

View File

@@ -0,0 +1,37 @@
"use client";
import {
ActionIcon,
AppShell,
FileButton,
Flex,
Footer,
Group,
Header,
Text,
} from "@mantine/core";
import { useRouter } from "next/navigation";
import { useState } from "react";
import ComponentKatalog_HeaderTamplate from "@/app_modules/katalog/component/header_tamplate";
export default function LayoutProfile_UpdateFotoBackground({
children,
}: {
children: any;
}) {
const router = useRouter();
return (
<>
<AppShell
header={<ComponentKatalog_HeaderTamplate title="Update Background" />}
>
{children}
</AppShell>
</>
);
}

View File

@@ -0,0 +1,37 @@
"use client";
import {
ActionIcon,
AppShell,
FileButton,
Flex,
Footer,
Group,
Header,
Text,
} from "@mantine/core";
import { useRouter } from "next/navigation";
import { useState } from "react";
import ComponentKatalog_HeaderTamplate from "@/app_modules/katalog/component/header_tamplate";
export default function UploadFotoProfileLayout({
children,
profileId,
}: {
children: any;
profileId: any;
}) {
const router = useRouter();
const [profile, setProfile] = useState(profileId);
return (
<>
<AppShell
header={<ComponentKatalog_HeaderTamplate title="Update Foto" />}
>
{children}
</AppShell>
</>
);
}

View File

@@ -0,0 +1,109 @@
"use client";
import {
AspectRatio,
Button,
Center,
FileButton,
Image,
Paper,
Stack,
Title,
} from "@mantine/core";
import { useState } from "react";
import { RouterProfile } from "@/app/lib/router_hipmi/router_katalog";
import { MODEL_PROFILE } from "../../model/interface";
import { IconCamera } from "@tabler/icons-react";
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
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";
export default function UploadFotoProfile({
dataProfile,
}: {
dataProfile: MODEL_PROFILE;
}) {
const router = useRouter();
const [profile, setProfile] = useState(dataProfile);
const [file, setFile] = useState<File | null>(null);
const [image, setImage] = useState<any | null>(null);
return (
<>
<Stack spacing={"xl"}>
<Paper p={"sm"} withBorder radius={"sm"} shadow="">
<Stack>
<AspectRatio ratio={1 / 1}>
<Image
alt="Foto"
src={
image
? image
: RouterProfile.api_foto_profile + profile.imagesId
}
/>
</AspectRatio>
<Center>
<FileButton
onChange={async (files: any | null) => {
try {
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);
} catch (error) {
console.log(error);
}
}}
accept="image/png,image/jpeg"
>
{(props) => (
<Button
{...props}
radius={"xl"}
variant="outline"
w={150}
leftIcon={<IconCamera />}
compact
>
Upload
</Button>
)}
</FileButton>
</Center>
</Stack>
</Paper>
<Button
radius={"xl"}
onClick={() => onUpdate(router, profile.id, file as any)}
>
Simpan
</Button>
</Stack>
</>
);
}
async function onUpdate(
router: AppRouterInstance,
profileId: string,
file: FormData
) {
const gambar = new FormData();
gambar.append("file", file as any);
await Profile_funUpdateFoto(profileId, gambar).then((res) => {
if (res.status === 200) {
ComponentGlobal_NotifikasiBerhasil(res.message);
router.back();
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}

View File

@@ -1,96 +0,0 @@
"use client";
import {
ActionIcon,
AppShell,
FileButton,
Flex,
Footer,
Group,
Header,
Text,
} from "@mantine/core";
import { IconArrowLeft, IconUpload } from "@tabler/icons-react";
import { useAtom } from "jotai";
import toast from "react-simple-toasts";
import { gs_profile } from "../state/global_state";
import { useShallowEffect } from "@mantine/hooks";
import { loadDataProfile } from "../fun/fun_get_profile";
import { funUploadFoto } from "../fun/upload_foto";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function UploadFotoProfileLayout({
children,
profileId
}: {
children: any;
profileId: any
}) {
const router = useRouter()
const [profile, setProfile] = useState(profileId)
return (
<>
{JSON.stringify(profileId)}
<AppShell
header={
<Header height={50} px={"sm"}>
<Group position="apart" h={50}>
<ActionIcon
variant="transparent"
onClick={() => router.push(`/dev/katalog/${profile}`)}
>
<IconArrowLeft />
</ActionIcon>
<Text>Upload Foto Profile</Text>
<ActionIcon variant="transparent"></ActionIcon>
</Group>
</Header>
}
footer={
<Footer height={70}>
<Flex align={"center"} justify={"center"} h={70} gap={"xl"}>
<Flex align={"center"} justify={"center"} h={70}>
<Flex direction={"column"} align={"center"}>
<FileButton
onChange={async (files) => {
const id = profile
if (!files) return toast("File Kosong");
const fd = new FormData();
fd.append("file", files);
const upFoto = await funUploadFoto(fd, id);
if (upFoto.success) {
toast("Upload berhasil");
router.push(`/dev/katalog/${profile}`)
// loadDataProfile(valUser.id, setUser, setProfile);
}
}}
accept="image/png,image/jpeg,image/webp"
>
{(props) => (
<ActionIcon {...props}>
<IconUpload />
</ActionIcon>
)}
</FileButton>
<Text fz={"sm"} fw={"bold"}>
Upload
</Text>
</Flex>
</Flex>
</Flex>
{/* */}
</Footer>
}
>
{children}
{/* {JSON.stringify(profile)} */}
</AppShell>
</>
);
}

View File

@@ -1,26 +0,0 @@
"use client";
import { AspectRatio, FileButton, Image, Paper, Title } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useAtom } from "jotai";
import { loadDataProfile } from "../fun/fun_get_profile";
import { gs_fotoProfile, gs_profile } from "../state/global_state";
import { getFotoProfile } from "../api/get-foto-profile";
import { useState } from "react";
import { ApiHipmi } from "@/app/lib/api";
import { myConsole } from "@/app/fun/my_console";
export default function UploadFotoProfile({imageUrl}: {imageUrl: any}) {
const [img, setImg] = useState(imageUrl)
return (
<>
{/* {JSON.stringify(foto)} */}
<AspectRatio ratio={1 / 1} >
<Paper p={"lg"} shadow="xl">
{img ? <Image alt="" src={`/img/${img}`} /> : <Image alt="" src={"/aset/avatar.png"} />}
</Paper>
</AspectRatio>
{/* {JSON.stringify(profile)} */}
</>
);
}