diff --git a/package.json b/package.json index 614f9ed1..15651cf3 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/public/img/0fb20fe0-af14-432b-87ca-094cecb4cb37.webp b/public/img/0fb20fe0-af14-432b-87ca-094cecb4cb37.webp new file mode 100644 index 00000000..e0c75142 Binary files /dev/null and b/public/img/0fb20fe0-af14-432b-87ca-094cecb4cb37.webp differ diff --git a/public/img/12040bbf-0319-41a0-a87e-268697f14a26.png b/public/img/12040bbf-0319-41a0-a87e-268697f14a26.png new file mode 100644 index 00000000..6e04e0ec Binary files /dev/null and b/public/img/12040bbf-0319-41a0-a87e-268697f14a26.png differ diff --git a/public/img/6d767045-b70f-41ef-9775-85407302443c.png b/public/img/6d767045-b70f-41ef-9775-85407302443c.png new file mode 100644 index 00000000..6e04e0ec Binary files /dev/null and b/public/img/6d767045-b70f-41ef-9775-85407302443c.png differ diff --git a/public/img/716c7533-d96b-4305-ae4f-52fb56dec512.png b/public/img/716c7533-d96b-4305-ae4f-52fb56dec512.png new file mode 100644 index 00000000..b4ef2a39 Binary files /dev/null and b/public/img/716c7533-d96b-4305-ae4f-52fb56dec512.png differ diff --git a/src/app/api/profile/foto/[name]/route.ts b/src/app/api/profile/foto/[name]/route.ts new file mode 100644 index 00000000..9d4a9101 --- /dev/null +++ b/src/app/api/profile/foto/[name]/route.ts @@ -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" + } + }) +} \ No newline at end of file diff --git a/src/app/dev/katalog/profile/upload/layout.tsx b/src/app/dev/katalog/profile/upload/layout.tsx new file mode 100644 index 00000000..371d9700 --- /dev/null +++ b/src/app/dev/katalog/profile/upload/layout.tsx @@ -0,0 +1,10 @@ +import { UploadFotoProfileLayout } from "@/app_modules/katalog/profile"; +import { AppShell } from "@mantine/core"; + +export default function Layout({ children }: { children: any }) { + return ( + <> + {children} + + ); +} diff --git a/src/app/dev/katalog/profile/upload/page.tsx b/src/app/dev/katalog/profile/upload/page.tsx new file mode 100644 index 00000000..66ced2af --- /dev/null +++ b/src/app/dev/katalog/profile/upload/page.tsx @@ -0,0 +1,9 @@ +import { UploadFotoProfile } from "@/app_modules/katalog/profile"; + +export default async function Page() { + return ( + <> + + + ); +} diff --git a/src/app/lib/api.ts b/src/app/lib/api.ts index 31500caf..e35dde8a 100644 --- a/src/app/lib/api.ts +++ b/src/app/lib/api.ts @@ -10,4 +10,5 @@ export const ApiHipmi = { //Profile create_profile: "/api/profile/create", edit_profile: "/api/profile/edit", + get_foto: "/api/profile/foto/", }; diff --git a/src/app_modules/home/view.tsx b/src/app_modules/home/view.tsx index acf582c2..9e719d9a 100644 --- a/src/app_modules/home/view.tsx +++ b/src/app_modules/home/view.tsx @@ -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(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 ( <> diff --git a/src/app_modules/katalog/profile/edit/view.tsx b/src/app_modules/katalog/profile/edit/view.tsx index 2c39c97d..4425460d 100644 --- a/src/app_modules/katalog/profile/edit/view.tsx +++ b/src/app_modules/katalog/profile/edit/view.tsx @@ -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)} */} - - + + res); - setProfile(data) - } \ No newline at end of file + await getProfile() + .then((res) => res) + .then((val) => { + setProfile(val); + }); +} diff --git a/src/app_modules/katalog/profile/fun/get_foto_profile.ts b/src/app_modules/katalog/profile/fun/get_foto_profile.ts new file mode 100644 index 00000000..d8d24f5a --- /dev/null +++ b/src/app_modules/katalog/profile/fun/get_foto_profile.ts @@ -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; +} diff --git a/src/app_modules/katalog/profile/fun/upload_foto.ts b/src/app_modules/katalog/profile/fun/upload_foto.ts new file mode 100644 index 00000000..043bd563 --- /dev/null +++ b/src/app_modules/katalog/profile/fun/upload_foto.ts @@ -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, + }; +} diff --git a/src/app_modules/katalog/profile/index.ts b/src/app_modules/katalog/profile/index.ts index d4f97edc..a5081aaf 100644 --- a/src/app_modules/katalog/profile/index.ts +++ b/src/app_modules/katalog/profile/index.ts @@ -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} \ No newline at end of file +export { + ProfileLayout, + CreateProfile, + getProfile, + EditProfileView, + EditProfileLayout, + UploadFotoProfile, + UploadFotoProfileLayout, +}; diff --git a/src/app_modules/katalog/profile/upload/layout.tsx b/src/app_modules/katalog/profile/upload/layout.tsx new file mode 100644 index 00000000..fc81d9d4 --- /dev/null +++ b/src/app_modules/katalog/profile/upload/layout.tsx @@ -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 ( + <> + + + router.push("/dev/katalog/view")} + > + + + Upload Foto Profile + + + + } + footer={ +
+ + + + { + 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) => ( + + + + )} + + + Upload + + + + + + {/* */} +
+ } + > + {children} + {/* {JSON.stringify(profile)} */} +
+ + ); +} diff --git a/src/app_modules/katalog/profile/upload/view.tsx b/src/app_modules/katalog/profile/upload/view.tsx new file mode 100644 index 00000000..f4096940 --- /dev/null +++ b/src/app_modules/katalog/profile/upload/view.tsx @@ -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(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)} */} + + + {foto ? : } + + + {/* {JSON.stringify(profile)} */} + + ); +} diff --git a/src/app_modules/katalog/view/view.tsx b/src/app_modules/katalog/view/view.tsx index 682cbc10..6fe31f5e 100644 --- a/src/app_modules/katalog/view/view.tsx +++ b/src/app_modules/katalog/view/view.tsx @@ -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(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 */}
- + {foto ? ( + + ) : ( + + )}
router.push("/dev/katalog/profile/upload")} + onClick={() => router.push("/dev/katalog/profile/upload")} sx={{ position: "relative" }} > @@ -70,6 +103,7 @@ export default function KatalogView() {
+ {/* Username dan Nama */} @@ -87,6 +121,7 @@ export default function KatalogView() { + {/* Info user: nomor, email dll */} diff --git a/yarn.lock b/yarn.lock index a2b17237..401c63e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"