upd: profile
Deskripsi - tampilan edit profile - integrasi api edit profile - tampilan edit password - integrasi api update password No Issues
This commit is contained in:
190
src/components/ProfileUser.tsx
Normal file
190
src/components/ProfileUser.tsx
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
import apiFetch from "@/lib/apiFetch";
|
||||||
|
import { Button, Divider, Flex, Group, Input, Modal, Stack, Title } from "@mantine/core";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import notification from "./notificationGlobal";
|
||||||
|
|
||||||
|
export default function ProfileUser() {
|
||||||
|
const [opened, setOpened] = useState(false);
|
||||||
|
const [openedPassword, setOpenedPassword] = useState(false);
|
||||||
|
const [pwdBaru, setPwdBaru] = useState("");
|
||||||
|
const [host, setHost] = useState({
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
phone: "",
|
||||||
|
roleId: "",
|
||||||
|
email: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [error, setError] = useState({
|
||||||
|
name: false,
|
||||||
|
email: false,
|
||||||
|
phone: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchHost() {
|
||||||
|
const { data } = await apiFetch.api.user.find.get();
|
||||||
|
setHost({
|
||||||
|
id: data?.user?.id ?? "",
|
||||||
|
name: data?.user?.name ?? "",
|
||||||
|
phone: data?.user?.phone ?? "",
|
||||||
|
roleId: data?.user?.roleId ?? "",
|
||||||
|
email: data?.user?.email ?? "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fetchHost();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
function onValidation({ kat, value }: { kat: 'name' | 'email' | 'phone', value: string, }) {
|
||||||
|
if (value.length < 1) {
|
||||||
|
setError({ ...error, [kat]: true });
|
||||||
|
} else {
|
||||||
|
setError({ ...error, [kat]: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
setHost({ ...host, [kat]: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUpdate() {
|
||||||
|
try {
|
||||||
|
const res = await apiFetch.api.user.update.post(host);
|
||||||
|
if (res.status === 200) {
|
||||||
|
setOpened(false);
|
||||||
|
notification({
|
||||||
|
title: "Success",
|
||||||
|
message: "Your profile have been saved",
|
||||||
|
type: "success",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Error",
|
||||||
|
message: "Failed to update profile",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
notification({
|
||||||
|
title: "Error",
|
||||||
|
message: "Failed to update profile",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUpdatePassword() {
|
||||||
|
try {
|
||||||
|
const res = await apiFetch.api.user["update-password"].post({ password: pwdBaru, id: host.id });
|
||||||
|
if (res.status === 200) {
|
||||||
|
setPwdBaru("");
|
||||||
|
setOpenedPassword(false);
|
||||||
|
notification({
|
||||||
|
title: "Success",
|
||||||
|
message: "Your password have been saved",
|
||||||
|
type: "success",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Error",
|
||||||
|
message: "Failed to update password",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
notification({
|
||||||
|
title: "Error",
|
||||||
|
message: "Failed to update password",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack gap={"md"}>
|
||||||
|
<Flex align="center" justify="space-between">
|
||||||
|
<Title order={4} c="gray.2">
|
||||||
|
Profile Pengguna
|
||||||
|
</Title>
|
||||||
|
<Group gap="md">
|
||||||
|
<Button variant="light" onClick={() => setOpened(true)}>Edit</Button>
|
||||||
|
<Button variant="light" onClick={() => setOpenedPassword(true)}>Ubah Password</Button>
|
||||||
|
</Group>
|
||||||
|
</Flex>
|
||||||
|
<Divider my={0} />
|
||||||
|
<Stack gap={"md"}>
|
||||||
|
<Group gap="xl" grow>
|
||||||
|
<Input.Wrapper label="Nama" description="" error="">
|
||||||
|
<Input value={host?.name ?? ""} readOnly />
|
||||||
|
</Input.Wrapper>
|
||||||
|
<Input.Wrapper label="Phone" description="" error="">
|
||||||
|
<Input value={host?.phone ?? ""} readOnly />
|
||||||
|
</Input.Wrapper>
|
||||||
|
</Group>
|
||||||
|
<Group gap="xl" grow>
|
||||||
|
<Input.Wrapper label="Email" description="" error="">
|
||||||
|
<Input value={host?.email ?? ""} readOnly />
|
||||||
|
</Input.Wrapper>
|
||||||
|
<Input.Wrapper label="Role" description="" error="">
|
||||||
|
<Input value={host?.roleId ?? ""} readOnly />
|
||||||
|
</Input.Wrapper>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
opened={opened}
|
||||||
|
onClose={() => setOpened(false)}
|
||||||
|
title={"Edit Profile"}
|
||||||
|
|
||||||
|
size={"lg"}
|
||||||
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
|
>
|
||||||
|
<Stack gap={"md"}>
|
||||||
|
<Input.Wrapper label="Nama" description="" error={error.name ? "Field is required" : ""}>
|
||||||
|
<Input value={host?.name ?? ""} onChange={(e) => onValidation({ kat: 'name', value: e.target.value })} />
|
||||||
|
</Input.Wrapper>
|
||||||
|
<Input.Wrapper label="Phone" description="" error={error.phone ? "Field is required" : ""}>
|
||||||
|
<Input value={host?.phone ?? ""} onChange={(e) => onValidation({ kat: 'phone', value: e.target.value })} />
|
||||||
|
</Input.Wrapper>
|
||||||
|
<Input.Wrapper label="Email" description="" error={error.email ? "Field is required" : ""}>
|
||||||
|
<Input value={host?.email ?? ""} onChange={(e) => onValidation({ kat: 'email', value: e.target.value })} />
|
||||||
|
</Input.Wrapper>
|
||||||
|
<Group grow>
|
||||||
|
<Button variant="light" onClick={() => setOpened(false)}>
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button variant="filled" onClick={() => handleUpdate()} disabled={error.name || error.phone || error.email}>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
opened={openedPassword}
|
||||||
|
onClose={() => setOpenedPassword(false)}
|
||||||
|
title={"Ubah Password"}
|
||||||
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
|
>
|
||||||
|
<Stack gap={"md"}>
|
||||||
|
<Input.Wrapper label="Password Baru" description="">
|
||||||
|
<Input value={pwdBaru} onChange={(e) => setPwdBaru(e.target.value)} />
|
||||||
|
</Input.Wrapper>
|
||||||
|
<Group grow>
|
||||||
|
<Button variant="light" onClick={() => setOpenedPassword(false)}>
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button variant="filled" onClick={() => handleUpdatePassword()} disabled={pwdBaru.length < 1}>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import DesaSetting from "@/components/DesaSetting";
|
import DesaSetting from "@/components/DesaSetting";
|
||||||
import KategoriPengaduan from "@/components/KategoriPengaduan";
|
import KategoriPengaduan from "@/components/KategoriPengaduan";
|
||||||
|
import ProfileUser from "@/components/ProfileUser";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
@@ -7,12 +8,10 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
Flex,
|
Flex,
|
||||||
Grid,
|
Grid,
|
||||||
Group,
|
|
||||||
Input,
|
|
||||||
NavLink,
|
NavLink,
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
Title,
|
Title
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
IconBuildingBank,
|
IconBuildingBank,
|
||||||
@@ -87,7 +86,7 @@ export default function DetailSettingPage() {
|
|||||||
) : type === "desa" ? (
|
) : type === "desa" ? (
|
||||||
<DesaSetting />
|
<DesaSetting />
|
||||||
) : (
|
) : (
|
||||||
<ProfilePage />
|
<ProfileUser />
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
@@ -96,37 +95,6 @@ export default function DetailSettingPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProfilePage() {
|
|
||||||
return (
|
|
||||||
<Stack gap={"md"}>
|
|
||||||
<Flex align="center" justify="space-between">
|
|
||||||
<Title order={4} c="gray.2">
|
|
||||||
Profile Pengguna
|
|
||||||
</Title>
|
|
||||||
<Button variant="light">Edit</Button>
|
|
||||||
</Flex>
|
|
||||||
<Divider my={0} />
|
|
||||||
<Stack gap={"md"}>
|
|
||||||
<Group gap="xl" grow>
|
|
||||||
<Input.Wrapper label="Nama" description="" error="">
|
|
||||||
<Input value={"Amalia Dwi Yustiani"} readOnly />
|
|
||||||
</Input.Wrapper>
|
|
||||||
<Input.Wrapper label="Phone" description="" error="">
|
|
||||||
<Input value={"08123456789"} readOnly />
|
|
||||||
</Input.Wrapper>
|
|
||||||
</Group>
|
|
||||||
<Group gap="xl" grow>
|
|
||||||
<Input.Wrapper label="Email" description="" error="">
|
|
||||||
<Input value={"amaliadwiyustiani@gmail.com"} readOnly />
|
|
||||||
</Input.Wrapper>
|
|
||||||
<Input.Wrapper label="Role" description="" error="">
|
|
||||||
<Input value={"Admin"} readOnly />
|
|
||||||
</Input.Wrapper>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function KategoriPengaduanPage() {
|
function KategoriPengaduanPage() {
|
||||||
const elements = [
|
const elements = [
|
||||||
|
|||||||
@@ -47,5 +47,59 @@ const UserRoute = new Elysia({
|
|||||||
description: "upsert user",
|
description: "upsert user",
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.post("/update-password", async ({ body }) => {
|
||||||
|
const { password, id } = body
|
||||||
|
const update = await prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
password
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Password updated successfully",
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
password: t.String({ minLength: 1, error: "password is required" }),
|
||||||
|
id: t.String({ minLength: 1, error: "id is required" })
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "update password",
|
||||||
|
description: "update password user",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.post("/update", async ({ body }) => {
|
||||||
|
const { name, phone, id, roleId } = body
|
||||||
|
const update = await prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
phone,
|
||||||
|
roleId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "User updated successfully",
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
name: t.String({ minLength: 1, error: "name is required" }),
|
||||||
|
phone: t.String({ minLength: 1, error: "phone is required" }),
|
||||||
|
id: t.String({ minLength: 1, error: "id is required" }),
|
||||||
|
roleId: t.String({ minLength: 1, error: "roleId is required" })
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "update",
|
||||||
|
description: "update user",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default UserRoute
|
export default UserRoute
|
||||||
Reference in New Issue
Block a user