Merge pull request #17 from bipproduction/katalog/profile

Katalog/profile
This commit is contained in:
Bagasbanuna02
2023-10-04 17:57:38 +08:00
committed by GitHub
20 changed files with 321 additions and 34 deletions

View File

@@ -20,6 +20,7 @@
"@types/node": "20.4.5",
"@types/react": "18.2.17",
"@types/react-dom": "18.2.7",
"@types/uuid": "^9.0.4",
"autoprefixer": "10.4.14",
"eslint": "8.45.0",
"eslint-config-next": "13.4.12",
@@ -33,6 +34,7 @@
"react-simple-toasts": "^5.10.0",
"tailwindcss": "3.3.3",
"typescript": "5.1.6",
"uuid": "^9.0.1",
"yaml": "^2.3.2"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -0,0 +1,11 @@
import { NextRequest, NextResponse } from "next/server";
import fs from 'fs'
export async function GET(req: NextRequest, { params }: { params: { name: string } }) {
const fl = fs.readFileSync(`./public/img/${params.name}`)
return new NextResponse(fl, {
headers: {
"Content-Type": "image/png"
}
})
}

View File

@@ -0,0 +1,10 @@
import { UploadFotoProfileLayout } from "@/app_modules/katalog/profile";
import { AppShell } from "@mantine/core";
export default function Layout({ children }: { children: any }) {
return (
<>
<UploadFotoProfileLayout>{children}</UploadFotoProfileLayout>
</>
);
}

View File

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

View File

@@ -10,4 +10,5 @@ export const ApiHipmi = {
//Profile
create_profile: "/api/profile/create",
edit_profile: "/api/profile/edit",
get_foto: "/api/profile/foto/",
};

View File

@@ -34,6 +34,8 @@ import { getProfile } from "../katalog/profile";
import { useRouter } from "next/navigation";
import { useAtom } from "jotai";
import { gs_token } from "./state/global_state";
import { g_getProfile } from "../katalog/profile/fun/fun_get_profile";
import { gs_profile } from "../katalog/profile/state/global_state";
const listHalaman = [
{
@@ -81,7 +83,7 @@ const listHalaman = [
export default function HomeView() {
const router = useRouter();
const [token, setToken] = useAtom(gs_token);
const [profile, setProfile] = useState<any | null>(null);
useShallowEffect(() => {
getUserId();
@@ -91,13 +93,10 @@ export default function HomeView() {
setToken(data);
}
const [profile, setProfile] = useAtom(gs_profile);
useShallowEffect(() => {
getUserProfile();
g_getProfile(setProfile);
}, []);
async function getUserProfile() {
const data = await getProfile();
setProfile(data);
}
return (
<>

View File

@@ -12,9 +12,9 @@ import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-simple-toasts";
import { gs_profile } from "../state/global_state";
import { g_getProfile } from "../fun/fun-get-profile";
import { g_getProfile } from "../fun/fun_get_profile";
export default function EditProfile({ data }: { data: any }) {
export default function EditProfile() {
const router = useRouter();
//Get data profile
@@ -24,6 +24,8 @@ export default function EditProfile({ data }: { data: any }) {
}, []);
async function onUpdate() {
const body = profile;
if (_.values(body).includes("")) return toast("Lengkapi data");
@@ -51,8 +53,8 @@ export default function EditProfile({ data }: { data: any }) {
<>
{/* {JSON.stringify(profile)} */}
<Stack px={"sm"}>
<TextInput label="Username" disabled value={data.User.username} />
<TextInput label="Nomor" disabled value={data.User.nomor} />
<TextInput label="Username" disabled value={profile.User.username} />
<TextInput label="Nomor" disabled value={profile.User.nomor} />
<TextInput
label="Nama"

View File

@@ -24,13 +24,7 @@ export async function getProfile() {
alamat: true,
jenisKelamin: true,
active: true,
ImageProfile: {
select: {
id: true,
url: true,
active: true,
},
},
imagesId: true,
User: {
select : {
username: true,

View File

@@ -1,3 +1,4 @@
import { myConsole } from "@/app/fun/my_console";
import { getProfile } from "..";
/**
@@ -6,6 +7,9 @@ import { getProfile } from "..";
* @returns data profile
*/
export async function g_getProfile(setProfile: any) {
const data = await getProfile().then((res) => res);
setProfile(data)
}
await getProfile()
.then((res) => res)
.then((val) => {
setProfile(val);
});
}

View File

@@ -0,0 +1,16 @@
"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

@@ -0,0 +1,52 @@
"use server";
import { myConsole } from "@/app/fun/my_console";
import prisma from "@/app/lib/prisma";
import fs from "fs";
import _ from "lodash";
import { cookies } from "next/headers";
import { v4 } from "uuid";
/**
*
* @param formData
* @returns upload gambar ke /public/img
*/
export async function funUploadFoto(formData: FormData, id: string) {
const file: any = formData.get("file");
const fName = file.name;
const fExt = _.lowerCase(file.name.split(".").pop());
const fRandomName = v4(fName) + "." + fExt;
myConsole(id);
myConsole(fExt);
const upload = await prisma.images.create({
data: {
url: fRandomName,
},
select: {
id: true,
url: true,
},
});
if (upload) {
await prisma.profile.update({
where: {
id: id,
},
data: {
imagesId: upload.id,
},
});
}
const upFolder = Buffer.from(await file.arrayBuffer());
fs.writeFileSync(`./public/img/${upload.url}`, upFolder);
return {
success: true,
data: upload,
};
}

View File

@@ -1,8 +1,17 @@
import ProfileLayout from "./create/layout";
import CreateProfile from "./create/view";
import {getProfile} from "./fun/api-get-profile";
import EditProfileLayout from './edit/layout';
import EditProfileView from './edit/view'
import { getProfile } from "./fun/api-get-profile";
import EditProfileLayout from "./edit/layout";
import EditProfileView from "./edit/view";
import UploadFotoProfile from "./upload/view";
import UploadFotoProfileLayout from "./upload/layout";
export {ProfileLayout, CreateProfile, getProfile, EditProfileView, EditProfileLayout}
export {
ProfileLayout,
CreateProfile,
getProfile,
EditProfileView,
EditProfileLayout,
UploadFotoProfile,
UploadFotoProfileLayout,
};

View File

@@ -0,0 +1,94 @@
"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 { g_getProfile } from "../fun/fun_get_profile";
import { funUploadFoto } from "../fun/upload_foto";
import { useRouter } from "next/navigation";
export default function UploadFotoProfileLayout({
children,
}: {
children: any;
}) {
const router = useRouter()
const [profile, setProfile] = useAtom(gs_profile);
useShallowEffect(() => {
g_getProfile(setProfile);
}, []);
return (
<>
<AppShell
header={
<Header height={50} px={"sm"}>
<Group position="apart" h={50}>
<ActionIcon
variant="transparent"
onClick={() => router.push("/dev/katalog/view")}
>
<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?.id
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/view")
// 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

@@ -0,0 +1,39 @@
"use client";
import { AspectRatio, FileButton, Image, Paper, Title } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useAtom } from "jotai";
import { g_getProfile } from "../fun/fun_get_profile";
import { gs_profile } from "../state/global_state";
import { getFotoProfile } from "../fun/get_foto_profile";
import { useState } from "react";
import { ApiHipmi } from "@/app/lib/api";
import { myConsole } from "@/app/fun/my_console";
export default function UploadFotoProfile() {
const [profile, setProfile] = useAtom(gs_profile);
useShallowEffect(() => {
g_getProfile(setProfile);
}, []);
const [foto, setFoto] = useState<any | null>(null);
useShallowEffect(() => {
if (profile?.imagesId === undefined || profile?.imagesId === null) {
myConsole("Waiting data");
} else {
getFotoProfile(profile?.imagesId).then((res) => setFoto(res?.url));
}
}, [profile?.imagesId]);
return (
<>
{/* {JSON.stringify(foto)} */}
<AspectRatio ratio={1 / 1} >
<Paper p={"lg"}>
{foto ? <Image alt="" src={ApiHipmi.get_foto + `${foto}`} /> : <Image alt="" src={"/aset/avatar.png"} />}
</Paper>
</AspectRatio>
{/* {JSON.stringify(profile)} */}
</>
);
}

View File

@@ -29,7 +29,9 @@ import { getProfile } from "../profile";
import { gs_profile } from "../profile/state/global_state";
import { myConsole } from "@/app/fun/my_console";
import { useAtom } from "jotai";
import { g_getProfile } from "../profile/fun/fun-get-profile";
import { g_getProfile } from "../profile/fun/fun_get_profile";
import { getFotoProfile } from "../profile/fun/get_foto_profile";
import { ApiHipmi } from "@/app/lib/api";
export default function KatalogView() {
const router = useRouter();
@@ -40,20 +42,51 @@ export default function KatalogView() {
g_getProfile(setProfile);
}, []);
const [foto, setFoto] = useState<any | null>(null);
useShallowEffect(() => {
if (profile?.imagesId === undefined || profile?.imagesId === null) {
myConsole("Waiting data");
} else {
getFotoProfile(profile?.imagesId).then((res) => setFoto(res?.url));
}
myConsole(profile?.imagesId);
}, [profile?.imagesId]);
return (
<>
{/* Background dan foto */}
<Box>
<Paper bg={"gray"} p={"md"}>
<Image alt="" src={"/aset/logo.png"} />
</Paper>
<Center>
<Image
alt=""
src={"/aset/avatar.png"}
height={100}
width={100}
sx={{ position: "absolute", marginBottom: 10, paddingBottom: 10 }}
/>
{foto ? (
<Image
radius={50}
alt=""
src={ApiHipmi.get_foto + `${foto}`}
height={100}
width={100}
sx={{
position: "absolute",
marginBottom: 10,
paddingBottom: 10,
}}
/>
) : (
<Image
radius={50}
alt=""
src={"/aset/avatar.png"}
height={100}
width={100}
sx={{
position: "absolute",
marginBottom: 10,
paddingBottom: 10,
}}
/>
)}
</Center>
<Center>
<ActionIcon
@@ -62,7 +95,7 @@ export default function KatalogView() {
variant="transparent"
bg={"gray"}
radius={50}
// onClick={() => router.push("/dev/katalog/profile/upload")}
onClick={() => router.push("/dev/katalog/profile/upload")}
sx={{ position: "relative" }}
>
<IconCamera color="black" size={20} />
@@ -70,6 +103,7 @@ export default function KatalogView() {
</Center>
</Box>
{/* Username dan Nama */}
<Group position="apart">
<Flex direction={"column"} mt={"lg"}>
<Text fz={"lg"} fw={"bold"}>
@@ -87,6 +121,7 @@ export default function KatalogView() {
</ActionIcon>
</Group>
{/* Info user: nomor, email dll */}
<Flex direction={"column"} pt={"lg"}>
<Grid>
<Grid.Col span={"content"}>

View File

@@ -756,6 +756,11 @@
"@types/mime" "*"
"@types/node" "*"
"@types/uuid@^9.0.4":
version "9.0.4"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.4.tgz#e884a59338da907bda8d2ed03e01c5c49d036f1c"
integrity sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==
"@typescript-eslint/parser@^5.42.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7"
@@ -3533,6 +3538,11 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
uuid@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
watchpack@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"