- PC: Loader chat
- QC: Auth , Profile, portofolio & user search
## No Issuue
git commit -m
This commit is contained in:
2024-05-16 10:03:34 +08:00
parent c57e495d68
commit 66b9902d97
74 changed files with 1336 additions and 622 deletions

View File

@@ -35,6 +35,7 @@
"@types/node": "20.4.5",
"@types/react": "18.2.17",
"@types/react-dom": "18.2.7",
"@types/react-virtualized": "^9.21.30",
"@types/uuid": "^9.0.4",
"autoprefixer": "10.4.14",
"bufferutil": "^4.0.8",
@@ -58,11 +59,13 @@
"react-easy-infinite-scroll-hook": "^2.1.4",
"react-fast-marquee": "^1.6.4",
"react-icons": "^5.0.1",
"react-infinite-scroll-component": "^6.1.0",
"react-international-phone": "^4.2.6",
"react-quill": "^2.0.0",
"react-responsive-carousel": "^3.2.23",
"react-simple-toasts": "^5.10.0",
"react-toastify": "^9.1.3",
"react-virtualized": "^9.22.5",
"socket.io-client": "^4.7.2",
"tailwindcss": "3.3.3",
"typescript": "5.1.6",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,12 @@
import prisma from "@/app/lib/prisma";
export async function GET(req: Request) {
const page = new URL(req.url).searchParams.get("page");
if (!page) return new Response("page require", { status: 400 });
const res = await prisma.projectCollaboration_Message.findMany({
take: 5,
skip: +page * 5 - 5,
});
return Response.json(res);
}

View File

@@ -1,6 +1,6 @@
import { AdminLayout } from "@/app_modules/admin/main_dashboard";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import React from "react";
export default async function Layout({
@@ -9,7 +9,7 @@ export default async function Layout({
children: React.ReactNode;
}) {
const userId = await user_getOneUserId()
const dataUser = await user_getOneById(userId)
const dataUser = await user_getOneByUserId(userId)
const userRole = dataUser?.masterUserRoleId
return (

View File

@@ -1,5 +1,7 @@
import adminColab_getOneRoomChatById from "@/app_modules/admin/colab/fun/get/get_one_room_chat_by_id";
import { Colab_GroupChatView } from "@/app_modules/colab";
import ColabViewChat from "@/app_modules/colab/detail/chat";
import colab_V2getListMessageByRoomId from "@/app_modules/colab/fun/chat/get_message_by_room_id";
import colab_getMessageByRoomId from "@/app_modules/colab/fun/get/room_chat/get_message_by_room_id";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import _ from "lodash";
@@ -7,20 +9,30 @@ import _ from "lodash";
export default async function Page({ params }: { params: { id: string } }) {
const roomId = params.id;
const userLoginId = await user_getOneUserId();
const dataRoom = (await adminColab_getOneRoomChatById({ roomId: roomId }))
const getData = (await adminColab_getOneRoomChatById({ roomId: roomId }))
.data;
const selectRoom = _.omit(dataRoom, [
const dataRoom = _.omit(getData, [
"ProjectCollaboration",
"ProjectCollaboration_AnggotaRoomChat",
]);
let listMsg = await colab_getMessageByRoomId({roomId: roomId, page: 1});
let listMsg = await colab_getMessageByRoomId({ roomId: roomId, page: 1 });
// const listMessage = await colab_V2getListMessageByRoomId({
// roomId: roomId,
// page: 1,
// });
return (
<>
{/* <ColabViewChat
listMsg={listMsg as any}
dataRoom={dataRoom as any}
userLoginId={userLoginId}
/> */}
<Colab_GroupChatView
userLoginId={userLoginId}
listMsg={listMsg}
selectRoom={selectRoom as any}
selectRoom={dataRoom as any}
/>
</>
);

View File

@@ -1,6 +1,6 @@
import { LayoutForum_Forumku } from "@/app_modules/forum";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import React from "react";
export default async function Layout({
@@ -11,7 +11,7 @@ export default async function Layout({
params: { id: string };
}) {
const authorId = params.id;
const dataAuthor = await user_getOneById(authorId);
const dataAuthor = await user_getOneByUserId(authorId);
return (
<>

View File

@@ -2,14 +2,14 @@ import { Forum_Forumku } from "@/app_modules/forum";
import { forum_getListPostingByAuhtorId } from "@/app_modules/forum/fun/get/get_list_posting_by_author_id";
import { forum_countOneTotalKomentarById } from "@/app_modules/forum/fun/count/count_one_total_komentar_by_id";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import _ from "lodash";
import { forum_countPostingByAuthorId } from "@/app_modules/forum/fun/count/count_posting_by_author_id";
export default async function Page({ params }: { params: { id: string } }) {
const authorId = params.id;
const userLoginId = await user_getOneUserId()
const dataAuthor = await user_getOneById(authorId);
const dataAuthor = await user_getOneByUserId(authorId);
const auhtorSelectedData = _.omit(dataAuthor, [
"Profile.email",
"Profile.alamat",

View File

@@ -1,6 +1,6 @@
import { LayoutForum_Main } from "@/app_modules/forum";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import React from "react";
export default async function Layout({
@@ -9,7 +9,7 @@ export default async function Layout({
children: React.ReactNode;
}) {
const authorId = await user_getOneUserId();
const dataAuthor = await user_getOneById(authorId);
const dataAuthor = await user_getOneByUserId(authorId);
return (
<>

View File

@@ -1,11 +1,11 @@
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { HomeLayout } from "@/app_modules/home";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { redirect } from "next/navigation";
export default async function Layout({ children }: { children: any }) {
const userId = await user_getOneUserId();
const dataUser = await user_getOneById(userId);
const dataUser = await user_getOneByUserId(userId);
return (
<>

View File

@@ -3,22 +3,25 @@ import { cookies } from "next/headers";
import { unsealData } from "iron-session";
import _ from "lodash";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { redirect } from "next/navigation";
import { RouterAdminDashboard } from "@/app/lib/router_hipmi/router_admin";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import ComponentGlobal_V2_LoadingPage from "@/app_modules/component_global/loading_page_v2";
export default async function Page() {
const userId = await user_getOneUserId();
const dataUser = await user_getOneById(userId);
const dataUser = await user_getOneByUserId(userId);
if (dataUser?.active === false) {
return redirect(RouterHome.home_user_non_active);
}
if (dataUser?.masterUserRoleId === "2" || dataUser?.masterUserRoleId === "3")
return redirect(RouterAdminDashboard.splash_admin);
// if (dataUser?.Profile === null) return <ComponentGlobal_V2_LoadingPage />;
// await new Promise((a, b) => {
// setTimeout(a, 4000);
// });

View File

@@ -12,13 +12,13 @@ import { funGetListPortofolio } from "@/app_modules/katalog/portofolio/fun/get/g
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { Profile_getOneById } from "@/app_modules/katalog/profile/fun/get/get_one_profile";
import { Profile_getOneProfileAndUserById } from "@/app_modules/katalog/profile/fun/get/get_one_user_profile";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
const config = yaml.parse(fs.readFileSync("config.yaml").toString());
export default async function Page({ params }: { params: { id: string } }) {
let profileId = params.id;
const authorId = await user_getOneUserId();
const dataUser = await user_getOneById(authorId)
const dataUser = await user_getOneByUserId(authorId)
const listPorto = await funGetListPortofolio(profileId);
const dataProfile = await Profile_getOneProfileAndUserById(profileId);

View File

@@ -1,10 +0,0 @@
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { CreateProfile } from "@/app_modules/katalog/profile";
export default async function Page({params}: {params: {id: string}}) {
const userId = await user_getOneUserId()
return <>
<CreateProfile userId={userId}/>
</>
}

View File

@@ -0,0 +1,12 @@
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { CreateProfile } from "@/app_modules/katalog/profile";
export default async function Page() {
const userId = await user_getOneUserId();
return (
<>
<CreateProfile userId={userId} />
</>
);
}

View File

@@ -2,12 +2,12 @@ import { RouterAdminDashboard } from "@/app/lib/router_hipmi/router_admin";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { Home_UserNonActive } from "@/app_modules/home";
import { user_getOneById } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { user_getOneByUserId } from "@/app_modules/home/fun/get/get_one_user_by_id";
import { redirect } from "next/navigation";
export default async function Page() {
const userId = await user_getOneUserId();
const dataUser = await user_getOneById(userId);
const dataUser = await user_getOneByUserId(userId);
if (dataUser?.active === true) {
return redirect(RouterHome.main_home);

View File

@@ -2,7 +2,7 @@ import { UserSearch_MainView } from "@/app_modules/user_search";
import { UserSearch_getListUser } from "@/app_modules/user_search/fun/get/get_list_user";
export default async function Page() {
const listUser = await UserSearch_getListUser()
const listUser = await UserSearch_getListUser({ name: "" });
return <UserSearch_MainView listUser={listUser as any} />;
}

View File

@@ -33,7 +33,7 @@ export default function RootStyleRegistry({
<body suppressHydrationWarning={true}>
<CacheProvider value={cache}>
<MantineProvider withGlobalStyles withNormalizeCSS>
<Notifications position="top-center" containerWidth="250px" />
<Notifications position="top-center" containerWidth={300} />
{children}
{/* <ToastContainer position="bottom-center" />
<AppNotif /> */}

View File

@@ -2,7 +2,7 @@ export const RouterProfile = {
katalog: "/dev/katalog/",
// create
create: "/dev/profile/create/",
create: "/dev/profile/create",
// edit
edit: "/dev/profile/edit/",

View File

@@ -5,34 +5,76 @@ import useInfiniteScroll, {
} from "react-easy-infinite-scroll-hook";
import { createItems, loadMore } from "./_util";
import { useShallowEffect } from "@mantine/hooks";
import { Center, Loader } from "@mantine/core";
import { Center, Loader, Text } from "@mantine/core";
// Beda Package
import InfiniteScroll from "react-infinite-scroll-component";
export default function App() {
const [data, setData] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(false);
useShallowEffect(() => {
setData(createItems());
}, []);
const ttlData = Array.from({ length: 21 });
const [list, setList] = useState<any[]>(ttlData);
const next = async (direction: ScrollDirection) => {
console.log("next", direction);
try {
setIsLoading(true);
const newData = await loadMore();
// useShallowEffect(() => {
// setData(createItems());
// }, []);
const d = direction === "up" ? [...newData, ...data] : [];
setData(d);
} finally {
setIsLoading(false);
}
// const next = async (direction: ScrollDirection) => {
// console.log("next", direction);
// try {
// setIsLoading(true);
// const newData = await loadMore();
// const d = direction === "up" ? [...newData, ...data] : [];
// setData(d);
// } finally {
// setIsLoading(false);
// }
// };
// const ref = useInfiniteScroll({
// next,
// rowCount: data.length,
// hasMore: { up: true },
// });
const fetchMoreData = () => {
setTimeout(() => {
setList(list.concat(Array.from({ length: 20 })));
}, 100);
};
const ref = useInfiniteScroll({
next,
rowCount: data.length,
hasMore: { up: true },
});
const style = {
height: 30,
border: "1px solid green",
margin: 6,
padding: 8,
};
return (
<>
<div id="scrollableDiv" style={{ height: "100vh", overflow: "auto" }}>
<InfiniteScroll
dataLength={list.length}
next={fetchMoreData}
hasMore={true}
loader={
<center>
<h4>Loading...</h4>
</center>
}
scrollableTarget="scrollableDiv"
>
{list.map((i, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
</>
);
return (
<Center>
@@ -40,7 +82,7 @@ export default function App() {
<Center>{isLoading && <Loader />}</Center>
<div
ref={ref as any}
// ref={ref as any}
className="List"
style={{
height: 500,

View File

@@ -181,7 +181,7 @@ function TableMenu({ listGroup }: { listGroup: any }) {
<Center>Industri</Center>
</th>
<th>
<Center>Jumlah Partisipan</Center>
<Center>Anggota Group</Center>
</th>
<th>
<Center>Aksi</Center>
@@ -222,7 +222,7 @@ function TableMenu({ listGroup }: { listGroup: any }) {
<ScrollArea h={"100%"}>
<Stack>
<Center>
<Title order={4}>Partisipan</Title>
<Title order={4}>Anggota</Title>
</Center>
<Stack>
{detailData?.ProjectCollaboration_AnggotaRoomChat?.map(

View File

@@ -45,5 +45,5 @@ export async function auth_funValidasi(nomor: string) {
return { status: 200, message: "Nomor Terverivikasi", role: cek.masterUserRoleId };
return { status: 200, message: "Nomor Terverifikasi", role: cek.masterUserRoleId };
}

View File

@@ -35,46 +35,24 @@ export default function Register({ dataOtp }: { dataOtp: any }) {
const focusTrapRef = useFocusTrap();
const [loading, setLoading] = useState(false);
// const onRegister = async () => {
// myConsole(value);
// const body = {
// username: _.lowerCase(value),
// nomor: nomor,
// };
// if (!body) return toast("Lengkapi username");
// if (body.username.length < 5) return toast("Username minimal 5 karakter");
// await fetch(ApiHipmi.register, {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(body),
// })
// .then((res) => res.json())
// .then((val) => {
// myConsole(val);
// if (val.status == 201) {
// toast("Pendaftaran Berhasil");
// return route.push("/dev/home");
// } else {
// return toast(val.message);
// }
// });
// };
async function onRegistarsi() {
const body = {
username: _.lowerCase(value),
username: value,
nomor: nomor,
};
// console.log(body);
if (_.values(body.username).includes(""))
if (body.username === "")
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Username");
if (body.username.length < 5)
return ComponentGlobal_NotifikasiPeringatan("Username minimal 5 krakter");
return ComponentGlobal_NotifikasiPeringatan("Username tidak sesuai");
if (_.values(body.username).includes(" "))
return ComponentGlobal_NotifikasiPeringatan(
"Username tidak sesuai",
3000
);
await Auth_funRegister(body).then(async (res) => {
if (res.status === 200) {
@@ -118,6 +96,18 @@ export default function Register({ dataOtp }: { dataOtp: any }) {
<TextInput
ref={focusTrapRef}
placeholder="Masukan Username"
error={
value.length > 0 && value.length < 5 ? (
<Text>Minimal 5 karakter</Text>
) : _.values(value).includes(" ") ? (
<Stack spacing={0}>
<Text>- Tidak boleh ada space</Text>
<Text>- Sambungkan huruf meggunakan karakter _</Text>
</Stack>
) : (
""
)
}
onChange={(val) => {
setValue(val.currentTarget.value);
}}

View File

@@ -11,7 +11,7 @@ export default function ComponentColab_NotedBox({
<Group>
<Text fz={10} fs={"italic"}>
<Text span inherit c={"red"}>
*{" "}
Alasan:{" "}
</Text>
{informasi}
</Text>

View File

@@ -0,0 +1,324 @@
"use client";
import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
import {
ActionIcon,
Box,
Button,
Card,
Center,
Code,
Grid,
Group,
Header,
Loader,
Paper,
ScrollArea,
Stack,
Text,
Textarea,
Title,
} from "@mantine/core";
import {
IconChevronLeft,
IconCircle,
IconInfoSquareRounded,
IconSend,
} from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import router from "next/router";
import React, { useRef, useState } from "react";
import {
MODEL_COLLABORATION_MESSAGE,
MODEL_COLLABORATION_ROOM_CHAT,
} from "../../model/interface";
import _ from "lodash";
import ComponentColab_IsEmptyData from "../../component/is_empty_data";
import colab_getMessageByRoomId from "../../fun/get/room_chat/get_message_by_room_id";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
import colab_funCreateMessageByUserId from "../../fun/create/room/fun_create_message_by_user_id";
import { useShallowEffect } from "@mantine/hooks";
import mqtt_client from "@/util/mqtt_client";
import useInfiniteScroll, {
ScrollDirection,
ScrollDirectionBooleanState,
} from "react-easy-infinite-scroll-hook";
import toast from "react-simple-toasts";
import colab_getOneMessageById from "../../fun/get/room_chat/get_one_message_by_id";
import { List } from "react-virtualized";
const list = Array(100).fill(0);
export default function ColabViewChat({
userLoginId,
listMsg,
dataRoom,
}: {
userLoginId: string;
listMsg: MODEL_COLLABORATION_MESSAGE[];
dataRoom?: MODEL_COLLABORATION_ROOM_CHAT | any;
}) {
// Tamplate app layout
const router = useRouter();
const [loadingBack, setLoadingBack] = useState(false);
const [loadingInfo, setLoadingInfo] = useState(false);
// State message
const [msg, setMsg] = useState("");
const [data, setData] = useState(listMsg);
// State infinite scroll
const [isLoading, setIsLoading] = useState(false);
const [totalPage, setTotalPage] = useState(1);
const [hasMore, setHasMore] = useState<ScrollDirectionBooleanState>({
up: true,
down: false,
});
// Kirim pesan
async function onSend() {
await colab_funCreateMessageByUserId(msg, dataRoom.id).then(async (res) => {
if (res.status === 200) {
const newData = await colab_getMessageByRoomId({
roomId: dataRoom?.id,
page: 1,
});
setData(newData as any);
setHasMore({ up: true });
setMsg("");
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
});
}
const next = async (direction: ScrollDirection) => {
try {
setIsLoading(true);
await new Promise((a) => setTimeout(a, 500));
const newData = await colab_getMessageByRoomId({
roomId: dataRoom?.id,
page: totalPage + 1,
});
setTotalPage(totalPage + 1);
// console.log(newData, "loading baru");
if (_.isEmpty(newData)) {
setHasMore({ up: false });
} else {
const d: any =
direction === "down" ? [...data, ...newData] : [...newData, ...data];
setData(d);
}
} finally {
setIsLoading(false);
}
};
const ref: any = useInfiniteScroll({
next,
rowCount: data.length,
hasMore,
scrollThreshold: 0.1,
});
return (
<>
<Box h={"100vh"}>
{/* Header */}
<Box
style={{
zIndex: 99,
}}
w={"100%"}
pos={"fixed"}
top={0}
h={"7vh"}
>
<Stack bg={"gray.2"} h={"100%"} justify="center" px={"sm"}>
<Grid grow gutter={"lg"}>
<Grid.Col span={2}>
<ActionIcon
loading={loadingBack ? true : false}
variant="transparent"
radius={"xl"}
onClick={() => {
setLoadingBack(true);
router.back();
}}
>
<IconChevronLeft />
</ActionIcon>
</Grid.Col>
<Grid.Col span={8}>
<Center>
<Title order={5} lineClamp={1}>
{dataRoom?.name}
</Title>
</Center>
</Grid.Col>
<Grid.Col span={2}>
<Group position="right">
<ActionIcon
loading={loadingInfo ? true : false}
variant="transparent"
radius={"xl"}
onClick={() => {
setLoadingInfo(true);
router.push(RouterColab.info_grup + dataRoom?.id);
}}
>
<IconInfoSquareRounded />
</ActionIcon>
</Group>
</Grid.Col>
</Grid>
</Stack>
</Box>
{/* Main View */}
<Box pos={"static"}>
<Box
style={{
height: "7vh",
display: "flex",
flexDirection: "column-reverse",
}}
/>
{/* Chat View */}
<Box h={"82vh"} px={"xs"}>
<Stack justify="flex-end" h={"100%"}>
<div
ref={ref as any}
style={{
overflowY: "auto",
}}
>
{isLoading && (
<Center>
<Loader size={20} color="gray" />
</Center>
)}
{_.isEmpty(data) ? (
<ComponentColab_IsEmptyData text="Belum ada pesan" />
) : (
data.map((e, i) => (
<Box key={i}>
{userLoginId === e?.User?.id ? (
<Group position="right">
<Paper key={e?.id} bg={"blue.2"} p={"sm"} mt={"sm"}>
<Stack spacing={0}>
<Text lineClamp={1} fw={"bold"} fz={"xs"}>
{e?.User?.Profile?.name}
</Text>
<div
dangerouslySetInnerHTML={{ __html: e?.message }}
/>
{/* <Group spacing={"xs"}>
<Text fz={7}>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "medium",
}).format(e.createdAt)}
</Text>
<IconCircle size={3} />
<Text fz={7}>
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "medium",
}).format(e.createdAt)}
</Text>
</Group> */}
</Stack>
</Paper>
</Group>
) : (
<Group>
<Paper key={e?.id} bg={"cyan.2"} p={"sm"} mt={"sm"}>
<Stack spacing={0}>
<Text lineClamp={1} fw={"bold"} fz={"xs"}>
{e?.User?.Profile?.name}
</Text>
<div
dangerouslySetInnerHTML={{ __html: e?.message }}
/>
{/* <Group spacing={"xs"}>
<Text fz={7}>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "medium",
}).format(e.createdAt)}
</Text>
<IconCircle size={3} />
<Text fz={7}>
{new Intl.DateTimeFormat("id-ID", {
dateStyle: "medium",
}).format(e.createdAt)}
</Text>
</Group> */}
</Stack>
</Paper>
</Group>
)}
</Box>
))
)}
</div>
</Stack>
</Box>
<Box
style={{
height: "11vh",
}}
/>
</Box>
{/* Footer */}
<Box
style={{
zIndex: 98,
}}
w={"100%"}
pos={"fixed"}
bottom={0}
h={"10vh"}
bg={"gray.2"}
>
<Stack justify="center" h={"100%"} px={"sm"}>
<Grid align="center">
<Grid.Col span={"auto"}>
<Textarea
value={msg}
minRows={1}
radius={"md"}
placeholder="Ketik pesan anda..."
onChange={(val) => {
setMsg(val.currentTarget.value);
}}
/>
</Grid.Col>
<Grid.Col span={"content"}>
<ActionIcon
disabled={msg ? false : true}
variant="filled"
bg={"cyan"}
radius={"xl"}
size={"xl"}
onClick={() => {
onSend();
}}
>
<IconSend size={20} />
</ActionIcon>
</Grid.Col>
</Grid>
</Stack>
</Box>
</Box>
</>
);
}

View File

@@ -4,7 +4,10 @@ import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
import {
ActionIcon,
Box,
Button,
Card,
Center,
Code,
Grid,
Group,
Header,
@@ -25,7 +28,10 @@ import {
import { useRouter } from "next/navigation";
import router from "next/router";
import { useRef, useState } from "react";
import { MODEL_COLLABORATION_ROOM_CHAT } from "../../model/interface";
import {
MODEL_COLLABORATION_MESSAGE,
MODEL_COLLABORATION_ROOM_CHAT,
} from "../../model/interface";
import _ from "lodash";
import ComponentColab_IsEmptyData from "../../component/is_empty_data";
import colab_getMessageByRoomId from "../../fun/get/room_chat/get_message_by_room_id";
@@ -36,6 +42,8 @@ import mqtt_client from "@/util/mqtt_client";
import useInfiniteScroll, {
ScrollDirection,
} from "react-easy-infinite-scroll-hook";
import toast from "react-simple-toasts";
import colab_getOneMessageById from "../../fun/get/room_chat/get_one_message_by_id";
export default function Colab_GroupChatView({
userLoginId,
@@ -50,61 +58,43 @@ export default function Colab_GroupChatView({
const [loadingBack, setLoadingBack] = useState(false);
const [loadingInfo, setLoadingInfo] = useState(false);
const [msg, setMsg] = useState("");
const [newMessage, setNewMessage] = useState<any>();
const [data, setData] = useState<any[]>(listMsg);
const [totalPage, setTotalPage] = useState(1);
const [isLoading, setIsLoading] = useState(false);
const [isGet, setIsGet] = useState(true);
const viewport = useRef<HTMLDivElement>(null);
const next = async (direction: ScrollDirection) => {
try {
setIsLoading(true);
await new Promise((a) => setTimeout(a, 500));
// const next = async (direction: ScrollDirection) => {
// try {
// setIsLoading(true);
// await new Promise((a) => setTimeout(a, 500));
const newData = await colab_getMessageByRoomId({
roomId: selectRoom?.id,
page: totalPage + 1,
});
setTotalPage(totalPage + 1);
// const newData = await colab_getMessageByRoomId({
// roomId: selectRoom?.id,
// page: totalPage + 1,
// });
// setTotalPage(totalPage + 1);
// console.log(newData, "loading baru");
// // console.log(newData, "loading baru");
if (_.isEmpty(newData)) {
setIsGet(false);
} else {
const d =
direction === "down" ? [...data, ...newData] : [...newData, ...data];
setData(d);
}
} finally {
setIsLoading(false);
}
};
// if (_.isEmpty(newData)) {
// setIsGet(false);
// } else {
// const d =
// direction === "down" ? [...data, ...newData] : [...newData, ...data];
// setData(d);
// }
// } finally {
// setIsLoading(false);
// }
// };
// const ref = useInfiniteScroll({
// next,
// rowCount: data.length,
// hasMore: { up: isGet },
// });
useShallowEffect(() => {
mqtt_client.subscribe(selectRoom.id);
mqtt_client.on("message", () => {
onList(setData);
});
}, [setData]);
async function onList(setData: any) {
await colab_getMessageByRoomId({
roomId: selectRoom?.id,
page: 1,
}).then((val) => {
setData(val);
setTotalPage(totalPage);
});
}
const ref = useInfiniteScroll({
next,
rowCount: data.length,
hasMore: { up: isGet },
scrollThreshold: 0.1,
});
async function onSend() {
await colab_funCreateMessageByUserId(msg, selectRoom.id).then(
@@ -112,6 +102,22 @@ export default function Colab_GroupChatView({
if (res.status === 200) {
mqtt_client.publish(selectRoom.id, msg);
setMsg("");
// const d = JSON.parse(JSON.stringify(res.data));
// setData([...data, ...[d]]);
await colab_getOneMessageById({
messageId: res.data?.id as any,
}).then((res) => {
// setNewMessage(res);
// console.log(res);
// const d = JSON.parse(JSON.stringify(res));
// setData([...data, ...[d]]);
mqtt_client.on("message", (a,b) => {
setData([...data, ...[res]])
})
});
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
@@ -119,10 +125,41 @@ export default function Colab_GroupChatView({
);
}
useShallowEffect(() => {
mqtt_client.subscribe(selectRoom.id);
// mqtt_client.on("message", (a, b) => {
// // loadDataNew(b.toString());
// // onList(b);
// onList2(newMessage);
// });
}, []);
async function onList2(dt: any) {
console.log(dt);
setData([...data, ...[dt]]);
}
// const loadDataNew = (dt: any) => {
// setData([JSON.parse(dt),...data]);
// };
async function onList(b: any) {
await colab_getMessageByRoomId({
roomId: selectRoom?.id,
page: 1,
}).then((val) => {
const d = JSON.parse(JSON.stringify(val[5]));
setData([...data, ...[d]]);
// setTotalPage(totalPage);
});
}
return (
<>
<Box h={"100vh"}>
{/* Header */}
<Box
style={{
zIndex: 99,
@@ -186,7 +223,7 @@ export default function Colab_GroupChatView({
<Box h={"80vh"}>
<Stack justify="flex-end" h={"100%"}>
<div
// ref={ref as any}
ref={ref as any}
style={{
overflowY: "auto",
}}
@@ -203,16 +240,16 @@ export default function Colab_GroupChatView({
<Box key={i}>
{userLoginId === e?.User?.id ? (
<Group position="right">
<Paper key={e.id} bg={"blue.2"} p={"sm"} mt={"sm"}>
<Paper key={e?.id} bg={"blue.2"} p={"sm"} mt={"sm"}>
<Stack spacing={0}>
<Text lineClamp={1} fw={"bold"} fz={"xs"}>
{e.User.Profile.name}
{e?.User?.Profile?.name}
</Text>
<div
dangerouslySetInnerHTML={{ __html: e.message }}
dangerouslySetInnerHTML={{ __html: e?.message }}
/>
<Group spacing={"xs"}>
{/* <Group spacing={"xs"}>
<Text fz={7}>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "medium",
@@ -224,21 +261,21 @@ export default function Colab_GroupChatView({
dateStyle: "medium",
}).format(e.createdAt)}
</Text>
</Group>
</Group> */}
</Stack>
</Paper>
</Group>
) : (
<Group>
<Paper key={e.id} bg={"cyan.2"} p={"sm"} mt={"sm"}>
<Paper key={e?.id} bg={"cyan.2"} p={"sm"} mt={"sm"}>
<Stack spacing={0}>
<Text lineClamp={1} fw={"bold"} fz={"xs"}>
{e.User.Profile.name}
{e?.User?.Profile?.name}
</Text>
<div
dangerouslySetInnerHTML={{ __html: e.message }}
dangerouslySetInnerHTML={{ __html: e?.message }}
/>
<Group spacing={"xs"}>
{/* <Group spacing={"xs"}>
<Text fz={7}>
{new Intl.DateTimeFormat("id-ID", {
timeStyle: "medium",
@@ -250,7 +287,7 @@ export default function Colab_GroupChatView({
dateStyle: "medium",
}).format(e.createdAt)}
</Text>
</Group>
</Group> */}
</Stack>
</Paper>
</Group>
@@ -281,6 +318,14 @@ export default function Colab_GroupChatView({
h={"10vh"}
bg={"gray.2"}
>
{/* <Button
onClick={() => {
const d: { [key: string]: any } = _.clone(data[0]);
setData([...data, d]);
}}
>
KIzRIM PESAN
</Button> */}
<Stack justify="center" h={"100%"} px={"sm"}>
<Grid align="center">
<Grid.Col span={"auto"}>
@@ -312,4 +357,35 @@ export default function Colab_GroupChatView({
</Box>
</>
);
// return (
// <Stack bg={"dark"}>
// <Button
// onClick={() => {
// const dd = _.clone(data[0]);
// dd.message = "apa kabar";
// console.log(dd);
// mqtt_client.publish(selectRoom.id, JSON.stringify(dd));
// }}
// >
// kirim pesan
// </Button>
// <div
// ref={ref as any}
// style={{
// overflowY: "auto",
// }}
// >
// {data.map((v, k) => (
// <Stack key={k}>
// <Card withBorder shadow="md" mt={"md"}>
// <Code>
// <pre>{JSON.stringify(v, null, 2)}</pre>
// </Code>
// </Card>
// </Stack>
// ))}
// </div>
// </Stack>
// );
}

View File

@@ -240,173 +240,212 @@ export default function Colab_DetailGrupDiskusi({
</>
);
// const [pesan, setPesan] = useState("");
// const [obrolan, setObrolan] = useState<any[]>(listMsg);
// const [scroll, scrollTo] = useWindowScroll();
// const [isLoading, setIsLoading] = useState(false);
// "use client";
// const next = async (direction: ScrollDirection) => {
// try {
// setIsLoading(true);
// await new Promise((a) => setTimeout(a, 500));
// const newData = await colab_getMessageByRoomId(roomId);
// import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
// import {
// ActionIcon,
// Box,
// Button,
// Card,
// Center,
// Code,
// Grid,
// Group,
// Header,
// Loader,
// Paper,
// ScrollArea,
// Stack,
// Text,
// Textarea,
// Title,
// } from "@mantine/core";
// import {
// IconChevronLeft,
// IconCircle,
// IconInfoSquareRounded,
// IconSend,
// } from "@tabler/icons-react";
// import { useRouter } from "next/navigation";
// import router from "next/router";
// import { useRef, useState } from "react";
// import {
// MODEL_COLLABORATION_MESSAGE,
// MODEL_COLLABORATION_ROOM_CHAT,
// } from "../../model/interface";
// import _ from "lodash";
// import ComponentColab_IsEmptyData from "../../component/is_empty_data";
// import colab_getMessageByRoomId from "../../fun/get/room_chat/get_message_by_room_id";
// import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/notif_global/notifikasi_gagal";
// import colab_funCreateMessageByUserId from "../../fun/create/room/fun_create_message_by_user_id";
// import { useShallowEffect } from "@mantine/hooks";
// import mqtt_client from "@/util/mqtt_client";
// import useInfiniteScroll, {
// ScrollDirection,
// } from "react-easy-infinite-scroll-hook";
// import toast from "react-simple-toasts";
// import colab_getOneMessageById from "../../fun/get/room_chat/get_one_message_by_id";
// setObrolan((prev) =>
// direction === "up" ? [...newData, ...prev] : [...prev, ...newData]
// );
// } finally {
// setIsLoading(false);
// const list = Array(100).fill(0);
// export default function ColabViewChat({
// userLoginId,
// listMsg,
// dataRoom,
// }: {
// userLoginId: string;
// listMsg: any;
// dataRoom?: MODEL_COLLABORATION_ROOM_CHAT;
// }) {
// // Tamplate app layout
// const router = useRouter();
// const [loadingBack, setLoadingBack] = useState(false);
// const [loadingInfo, setLoadingInfo] = useState(false);
// // State message
// const [msg, setMsg] = useState("");
// const [data, setData] = useState(listMsg);
// const [ls, setLs] = useState(list);
// const viewport = useRef<HTMLDivElement>(null);
// const scrollBottom = () => {
// viewport.current?.scrollTo({
// top: viewport.current.scrollHeight,
// behavior: "smooth",
// });
// };
// // Kirim pesan
// async function onSend() {
// setMsg("");
// setLs([...[msg], ...ls]);
// scrollBottom();
// }
// };
// const ref = useInfiniteScroll({
// next,
// rowCount: obrolan.length,
// hasMore: { up: true },
// });
// return (
// <>
// <Box h={"100vh"}>
// {/* Header */}
// useShallowEffect(() => {
// mqtt_client.subscribe(roomId);
// <Box
// style={{
// zIndex: 99,
// }}
// w={"100%"}
// pos={"fixed"}
// top={0}
// h={"7vh"}
// >
// <Stack bg={"gray.2"} h={"100%"} justify="center" px={"sm"}>
// <Grid grow gutter={"lg"}>
// <Grid.Col span={2}>
// <ActionIcon
// loading={loadingBack ? true : false}
// variant="transparent"
// radius={"xl"}
// onClick={() => {
// setLoadingBack(true);
// router.back();
// }}
// >
// <IconChevronLeft />
// </ActionIcon>
// </Grid.Col>
// <Grid.Col span={8}>
// <Center>
// <Title order={5} lineClamp={1}>
// {dataRoom?.name}
// </Title>
// </Center>
// </Grid.Col>
// <Grid.Col span={2}>
// <Group position="right">
// <ActionIcon
// loading={loadingInfo ? true : false}
// variant="transparent"
// radius={"xl"}
// onClick={() => {
// setLoadingInfo(true);
// router.push(RouterColab.info_grup + dataRoom?.id);
// }}
// >
// <IconInfoSquareRounded />
// </ActionIcon>
// </Group>
// </Grid.Col>
// </Grid>
// </Stack>
// </Box>
// mqtt_client.on("message", (data: any, msg: any) => {
// onList(setObrolan);
// });
// }, [setObrolan]);
// {/* Main View */}
// async function onList(setObrolan: any) {
// await colab_getMessageByRoomId(roomId).then((val) => setObrolan(val));
// }
// async function onSend() {
// await colab_funCreateMessageByUserId(pesan, roomId).then(async (res) => {
// if (res.status === 200) {
// mqtt_client.publish(roomId, pesan);
// scrollIntoView();
// setPesan("");
// } else {
// ComponentGlobal_NotifikasiGagal(res.message);
// }
// });
// }
// return (
// <>
// <Box h={"79vh"}>
// {/* <pre>{JSON.stringify(listMsg.map((e) => e.createdAt), null,2)}</pre> */}
// {/* <ScrollArea h={"79vh"} scrollbarSize={2}>
// </ScrollArea> */}
// <Box>
// {_.isEmpty(obrolan) ? (
// <ComponentColab_IsEmptyData text="Belum Ada Pesan" />
// ) : (
// <div
// ref={ref as any}
// <Box pos={"static"}>
// <Box
// style={{
// overflowY: "scroll",
// height: "80vh",
// height: "7vh",
// }}
// >
// {isLoading ? (
// <Center>
// <Loader color="gray" />
// </Center>
// ) : (
// ""
// )}
// {obrolan.map((e) => (
// <Box key={e.id} pt={"lg"}>
// {e?.User.id === userLoginId ? (
// <Group position="right" ref={targetRef as any}>
// <Paper key={e.id} bg={"blue.2"} p={"sm"}>
// <Stack spacing={0}>
// <Text lineClamp={1} fw={"bold"} fz={"xs"}>
// {e.User.Profile.name}
// </Text>
// <Text>{e.message}</Text>
// <Group spacing={"xs"}>
// <Text fz={7}>
// {new Intl.DateTimeFormat("id-ID", {
// timeStyle: "medium",
// }).format(e.createdAt)}
// </Text>
// <IconCircle size={3} />
// <Text fz={7}>
// {new Intl.DateTimeFormat("id-ID", {
// dateStyle: "medium",
// }).format(e.createdAt)}
// </Text>
// </Group>
// </Stack>
// </Paper>
// </Group>
// ) : (
// <Group position="left">
// <Paper key={e.id} bg={"cyan.2"} p={"sm"} mr={"lg"}>
// <Stack spacing={0}>
// <Text lineClamp={1} fw={"bold"} fz={10}>
// {e.User.Profile.name}
// </Text>
// <Text>{e.message}</Text>
// <Group spacing={"xs"}>
// <Text fz={7}>
// {new Intl.DateTimeFormat("id-ID", {
// timeStyle: "medium",
// }).format(e.createdAt)}
// </Text>
// <IconCircle size={3} />
// <Text fz={7}>
// {new Intl.DateTimeFormat("id-ID", {
// dateStyle: "medium",
// }).format(e.createdAt)}
// </Text>
// </Group>
// </Stack>
// </Paper>
// </Group>
// )}
// </Box>
// ))}
// </div>
// )}
// </Box>
// </Box>
// />
// {/* Chat View */}
// <Box h={"83vh"} bg={"blue"}>
// <ScrollArea h={"100%"} viewportRef={viewport}>
// {ls.map((e, i) => (
// <Text key={i}>{`${e + 1 + i++}`}</Text>
// ))}
// </ScrollArea>
// </Box>
// <Box
// style={{
// height: "10vh",
// }}
// />
// </Box>
// {/* Footer */}
// <Box
// style={{
// zIndex: 98,
// }}
// w={"100%"}
// pos={"fixed"}
// bottom={0}
// h={"10vh"}
// bg={"gray.2"}
// >
// <Stack justify="center" h={"100%"} px={"sm"}>
// <Grid align="center">
// <Grid.Col span={"auto"}>
// <Textarea
// minRows={1}
// radius={"md"}
// placeholder="Ketik pesan anda..."
// onChange={(val) => {
// setMsg(val.currentTarget.value);
// }}
// />
// </Grid.Col>
// <Grid.Col span={"content"}>
// <ActionIcon
// disabled={msg ? false : true}
// variant="filled"
// bg={"cyan"}
// radius={"xl"}
// size={"xl"}
// onClick={() => {
// onSend();
// }}
// >
// <IconSend size={20} />
// </ActionIcon>
// </Grid.Col>
// </Grid>
// </Stack>
// </Box>
// </Box>
// </>
// );
// }
// <Affix
// bg={"gray.2"}
// h={"10vh"}
// position={{ bottom: rem(0) }}
// w={"100%"}
// zIndex={99}
// p={"xs"}
// >
// <Stack justify="center" h={"100%"} px={"sm"}>
// <Grid align="center">
// <Grid.Col span={"auto"}>
// <Textarea
// minRows={1}
// radius={"md"}
// placeholder="Ketik pesan anda..."
// value={pesan}
// onChange={(val) => setPesan(val.currentTarget.value)}
// />
// </Grid.Col>
// <Grid.Col span={"content"}>
// <ActionIcon
// disabled={pesan === "" ? true : false}
// variant="filled"
// bg={"cyan"}
// radius={"xl"}
// size={"xl"}
// onClick={() => {
// onSend();
// }}
// >
// <IconSend size={20} />
// </ActionIcon>
// </Grid.Col>
// </Grid>
// </Stack>
// </Affix>
// </>
// );
}

View File

@@ -0,0 +1,65 @@
"use server";
import prisma from "@/app/lib/prisma";
import _, { ceil } from "lodash";
export default async function colab_V2getListMessageByRoomId({
roomId,
page,
}: {
roomId: string;
page: number;
}) {
// console.log(page);
const lewat = page * 6 - 6;
const ambil = 6;
const awal = await prisma.projectCollaboration_Message.count({
where: {
isActive: true,
User: {
active: true,
},
},
});
const getData = await prisma.projectCollaboration_Message.findMany({
skip: lewat,
take: ambil,
orderBy: {
createdAt: "desc",
},
where: {
isActive: true,
User: {
active: true,
},
},
select: {
id: true,
createdAt: true,
isActive: true,
message: true,
isFile: true,
User: {
select: {
id: true,
Profile: {
select: {
name: true,
},
},
},
},
userId: true,
},
});
const allData = {
data: _.reverse(getData),
nPage: ceil(awal / ambil),
};
return allData;
}

View File

@@ -1,7 +1,9 @@
"use server";
import prisma from "@/app/lib/prisma";
import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
import { revalidatePath } from "next/cache";
export default async function colab_funCreateMessageByUserId(
message: string,
@@ -14,8 +16,28 @@ export default async function colab_funCreateMessageByUserId(
message: message,
projectCollaboration_RoomChatId: roomId,
},
select: {
id: true,
createdAt: true,
isActive: true,
message: true,
isFile: true,
User: {
select: {
id: true,
Profile: {
select: {
id: true,
name: true,
},
},
},
},
},
});
if (!msg) return { status: 400, message: "Pesan Gagal Dikirim" };
return { status: 200, message: "Pesan Berhasil Dikirim" };
revalidatePath(RouterColab.group_chat + roomId);
return { data: msg, status: 200, message: "Pesan Berhasil Dikirim" };
}

View File

@@ -1,7 +1,9 @@
"use server";
import prisma from "@/app/lib/prisma";
import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
import _ from "lodash";
import { revalidatePath } from "next/cache";
export default async function colab_getMessageByRoomId({
roomId,
@@ -10,8 +12,9 @@ export default async function colab_getMessageByRoomId({
roomId: string;
page: number;
}) {
const lewat = page * 6 - 6;
const ambil = 6;
const lewat = page * 10 - 10;
const ambil = 10;
const getList = await prisma.projectCollaboration_Message.findMany({
orderBy: {
createdAt: "desc",
@@ -41,8 +44,7 @@ export default async function colab_getMessageByRoomId({
},
});
const reverse = _.reverse(getList)
const reverse = _.reverse(getList);
return reverse;
}

View File

@@ -0,0 +1,36 @@
"use server";
import prisma from "@/app/lib/prisma";
export default async function colab_getOneMessageById({
messageId,
}: {
messageId: string;
}) {
// console.log(messageId);
const getOne = await prisma.projectCollaboration_Message.findFirst({
where: {
id: messageId,
},
select: {
id: true,
createdAt: true,
isActive: true,
message: true,
isFile: true,
User: {
select: {
id: true,
Profile: {
select: {
id: true,
name: true,
},
},
},
},
},
});
return getOne;
}

View File

@@ -70,3 +70,14 @@ export interface MODEL_COLLABORATION_NOTIFIKSI {
note: string;
ProjectCollaboration: MODEL_COLLABORATION;
}
export interface MODEL_COLLABORATION_MESSAGE {
id: string;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
userId: string;
message: string;
isFile: boolean;
User: MODEL_USER;
}

View File

@@ -35,10 +35,10 @@ export default function AppComponentGlobal_LayoutTamplate({
zIndex: 99,
}}
w={"100%"}
bg={"black"}
// bg={"black"}
pos={"sticky"}
top={0}
h={50}
h={"7vh"}
>
{header}
</Box>
@@ -46,29 +46,36 @@ export default function AppComponentGlobal_LayoutTamplate({
{/* Children */}
<Box p={"sm"} pos={"static"}>
<Stack>
{children}
<Box
style={{
height: "10vh",
}}
></Box>
{footer ? (
<Box
style={{
height: "10vh",
}}
></Box>
) : (
""
)}
</Stack>
</Box>
{/* Footer */}
{footer ? <Box
style={{
zIndex: 98,
}}
w={"100%"}
bg={"black"}
pos={"fixed"}
bottom={0}
h={"10vh"}
>
{footer}
</Box> : ""}
{footer ? (
<Box
style={{
zIndex: 98,
}}
w={"100%"}
bg={"black"}
pos={"fixed"}
bottom={0}
h={"10vh"}
>
{footer}
</Box>
) : (
""
)}
</Box>
</>
);

View File

@@ -2,7 +2,7 @@
import prisma from "@/app/lib/prisma";
export async function user_getOneById(userId: string) {
export async function user_getOneByUserId(userId: string) {
const data = await prisma.user.findFirst({
where: {
id: userId,

View File

@@ -41,7 +41,7 @@ export default function HomeLayout({
children: React.ReactNode;
}) {
const router = useRouter();
const [user, setUser] = useState(dataUser);
// const [user, setUser] = useState(dataUser);
const [loadingProfil, setLoadingProfile] = useState(false);
const [loadingUS, setLoadingUS] = useState(false);
const listFooter = [
@@ -73,7 +73,7 @@ export default function HomeLayout({
align="center"
spacing={0}
onClick={() => {
if (user?.Profile === null) {
if (dataUser?.Profile === null) {
ComponentGlobal_NotifikasiPeringatan("Lengkapi Profile");
} else {
setLoadingUS(true);
@@ -104,15 +104,17 @@ export default function HomeLayout({
spacing={2}
onClick={() => {
setLoadingProfile(true);
if (user?.Profile === null) {
router.push(RouterProfile.create + `${user.id}`);
if (dataUser?.Profile === null) {
router.push(RouterProfile.create + `${dataUser.id}`);
} else {
router.push(RouterProfile.katalog + `${user.Profile.id}`);
router.push(
RouterProfile.katalog + `${dataUser.Profile.id}`
);
}
}}
>
<ActionIcon variant={"transparent"}>
{user?.Profile === null ? (
{dataUser?.Profile === null ? (
<IconUserCircle color="white" />
) : (
<Avatar
@@ -125,7 +127,7 @@ export default function HomeLayout({
}}
src={
RouterProfile.api_foto_profile +
`${user?.Profile.imagesId}`
`${dataUser?.Profile.imagesId}`
}
/>
)}
@@ -197,7 +199,7 @@ export default function HomeLayout({
align="center"
spacing={0}
onClick={() => {
if (user?.Profile === null) {
if (dataUser?.Profile === null) {
ComponentGlobal_NotifikasiPeringatan(
"Lengkapi Profile"
);
@@ -231,17 +233,17 @@ export default function HomeLayout({
spacing={2}
onClick={() => {
setLoadingProfile(true);
if (user?.Profile === null) {
router.push(RouterProfile.create + `${user.id}`);
if (dataUser?.Profile === null) {
router.push(RouterProfile.create);
} else {
router.push(
RouterProfile.katalog + `${user.Profile.id}`
RouterProfile.katalog + `${dataUser.Profile.id}`
);
}
}}
>
<ActionIcon variant={"transparent"}>
{user?.Profile === null ? (
{dataUser?.Profile === null ? (
<IconUserCircle color="white" />
) : (
<Avatar
@@ -254,7 +256,7 @@ export default function HomeLayout({
}}
src={
RouterProfile.api_foto_profile +
`${user?.Profile.imagesId}`
`${dataUser?.Profile.imagesId}`
}
/>
)}
@@ -271,100 +273,4 @@ export default function HomeLayout({
</Box>
</>
);
return (
<>
<AppShell
header={
<Header height={50} bg={"dark"}>
<Group position="center" align="center" h={50} p={"sm"}>
<Text color="white" fw={"bold"}>
HIPMI
</Text>
{/* <Logout/> */}
</Group>
</Header>
}
footer={
<Footer height={70} bg={"dark"}>
<Grid p={"xs"} bg={"blue"}>
<Grid.Col
bg={"red"}
span={"auto"}
onClick={() => {
if (user?.Profile === null) {
ComponentGlobal_NotifikasiPeringatan("Lengkapi Profile");
} else {
setLoadingUS(true);
// router.push(RouterProfile.katalog + `${user.Profile.id}`);
router.push(RouterUserSearch.main);
}
}}
>
{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
bg={"cyan"}
span={"auto"}
onClick={() => {
setLoadingProfile(true);
if (user?.Profile === null) {
router.push(RouterProfile.create + `${user.id}`);
} else {
router.push(RouterProfile.katalog + `${user.Profile.id}`);
}
}}
>
{loadingProfil ? (
<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>
}
>
{children}
</AppShell>
</>
);
}

View File

@@ -157,7 +157,9 @@ export default function HomeView({ dataUser }: { dataUser: MODEL_USER }) {
>
{e.icon}
</ActionIcon>
<Text c={e.link === "" ? "gray" : "teal"} fz={"sm"}>{e.name}</Text>
<Text c={e.link === "" ? "gray" : "teal"} fz={"sm"}>
{e.name}
</Text>
</Flex>
</Paper>
))}

View File

@@ -0,0 +1,2 @@
export var validRegex =
/^([a-zA-Z0-9\.!#$%&'*+/=?^_`{|}~-]+)@([a-zA-Z0-9])+.([a-z]+)(.[a-z]+)?$/;

View File

@@ -17,7 +17,7 @@ import {
import { ProfileView } from "../profile";
import { ListPortofolioView } from "../portofolio";
import { MODEL_PROFILE_OLD } from "@/app_modules/home/model/user_profile";
import { LIST_PORTOFOLIO } from "@/app_modules/model_global/portofolio";
import { MODEL_PORTOFOLIO_Lama } from "@/app_modules/model_global/portofolio";
import User_Logout from "@/app_modules/auth/logout/view";
import { MODEL_PORTOFOLIO } from "../portofolio/model/interface";
import { MODEL_PROFILE } from "../profile/model/interface";
@@ -28,10 +28,9 @@ export default function KatalogView({
userLoginId,
}: {
profile: MODEL_PROFILE;
listPorto: LIST_PORTOFOLIO;
listPorto: MODEL_PORTOFOLIO;
userLoginId: string;
}) {
return (
<>
<Stack>
@@ -41,9 +40,9 @@ export default function KatalogView({
profile={profile}
userLoginId={userLoginId}
/>
<Stack my={"lg"} w={"100%"}>
{profile?.User.id === userLoginId ? <User_Logout /> : ""}
</Stack>
<Stack my={"lg"} w={"100%"}>
{profile?.User.id === userLoginId ? <User_Logout /> : ""}
</Stack>
</Stack>
</>
);

View File

@@ -72,6 +72,7 @@ export default function CreatePortofolio({
withAsterisk
label="Nama Bisnis"
placeholder="Nama bisnis"
error={value.namaBisnis.length > 100 ? "Maksimal 100 karakter" : ""}
onChange={(val) => {
setValue({
...value,
@@ -98,6 +99,9 @@ export default function CreatePortofolio({
withAsterisk
label="Alamat Kantor"
placeholder="Alamat kantor"
error={
value.alamatKantor.length > 100 ? "Maksimal 100 karakter" : ""
}
onChange={(val) => {
setValue({
...value,
@@ -108,7 +112,7 @@ export default function CreatePortofolio({
<TextInput
withAsterisk
label="Nomor Telepon Kantor"
placeholder="62 xxx xxx xxx"
placeholder="Nomor telepon kantor"
type="number"
onChange={(val) => {
setValue({
@@ -124,6 +128,7 @@ export default function CreatePortofolio({
withAsterisk
label="Deskripsi"
placeholder="Deskripsi singkat mengenai usaha"
error={value.deskripsi.length > 150 ? "Maksimal 150 karakter" : ""}
onChange={(val) => {
setValue({
...value,
@@ -270,7 +275,11 @@ async function onSubmit(
if (_.values(porto).includes(""))
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data");
if (!file)
return ComponentGlobal_NotifikasiPeringatan("Lengkapi logo binnis");
return ComponentGlobal_NotifikasiPeringatan("Lengkapi logo bisnis");
if (porto.namaBisnis.length > 100) return null;
if (porto.alamatKantor.length > 100) return null;
if (porto.deskripsi.length > 150) return null;
const gambar = new FormData();
gambar.append("file", file as any);

View File

@@ -12,6 +12,7 @@ import { useRouter } from "next/navigation";
import { Portofolio_funEditDataBisnis } from "../../fun/edit/fun_edit_data_bisnis_by_id";
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 Portofolio_EditDataBisnis({
dataPorto,
@@ -21,15 +22,9 @@ export default function Portofolio_EditDataBisnis({
listBidang: MODEL_PORTOFOLIO_BIDANG_BISNIS[];
}) {
const router = useRouter();
const [porto, setPorto] = useState(dataPorto);
const [value, setValue] = useState(dataPorto);
const [loading, setLoading] = useState(false);
// const [value, setPorto] = useState({
// namaBisnis: "",
// masterBidangBisnisId: "",
// alamatKantor: "",
// tlpn: "",
// deskripsi: "",
// });
return (
<>
{/* <pre>{JSON.stringify(porto, null, 2)}</pre> */}
@@ -37,19 +32,20 @@ export default function Portofolio_EditDataBisnis({
<Stack>
<TextInput
withAsterisk
value={porto.namaBisnis}
value={value.namaBisnis}
label="Nama Bisnis"
placeholder="Nama bisnis"
error={value.namaBisnis.length > 100 ? "Maksimal 100 karakter" : ""}
onChange={(val) => {
setPorto({
...porto,
setValue({
...value,
namaBisnis: val.target.value,
});
}}
/>
<Select
withAsterisk
value={porto.MasterBidangBisnis.id}
value={value.MasterBidangBisnis.id}
label="Bidang Bisnis"
placeholder="Pilih salah satu bidang bisnis"
data={listBidang.map((e) => ({
@@ -57,8 +53,8 @@ export default function Portofolio_EditDataBisnis({
label: e.name,
}))}
onChange={(val) => {
setPorto({
...(porto as any),
setValue({
...(value as any),
MasterBidangBisnis: {
id: val,
},
@@ -67,25 +63,28 @@ export default function Portofolio_EditDataBisnis({
/>
<TextInput
withAsterisk
value={porto.alamatKantor}
value={value.alamatKantor}
label="Alamat Kantor"
placeholder="Alamat kantor"
error={
value.alamatKantor.length > 100 ? "Maksimal 100 karakter" : ""
}
onChange={(val) => {
setPorto({
...porto,
setValue({
...value,
alamatKantor: val.target.value,
});
}}
/>
<TextInput
withAsterisk
value={porto.tlpn}
value={value.tlpn}
label="Nomor Telepon Kantor"
placeholder="62 xxx xxx xxx"
type="number"
onChange={(val) => {
setPorto({
...porto,
setValue({
...value,
tlpn: val.target.value,
});
}}
@@ -95,12 +94,13 @@ export default function Portofolio_EditDataBisnis({
minRows={2}
maxRows={5}
withAsterisk
value={porto.deskripsi}
value={value.deskripsi}
label="Deskripsi"
placeholder="Deskripsi singkat mengenai usaha"
error={value.deskripsi.length > 150 ? "Maksimal 150 karakter" : ""}
onChange={(val) => {
setPorto({
...porto,
setValue({
...value,
deskripsi: val.target.value,
});
}}
@@ -111,7 +111,7 @@ export default function Portofolio_EditDataBisnis({
loading={loading ? true : false}
loaderPosition="center"
onClick={() => {
onUpdate(router, porto as any, setLoading);
onUpdate(router, value as any, setLoading);
}}
>
Update
@@ -126,6 +126,13 @@ async function onUpdate(
data: MODEL_PORTOFOLIO,
setLoading: any
) {
if (_.values(data).includes(""))
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data");
if (data.namaBisnis.length > 100) return null;
if (data.alamatKantor.length > 100) return null;
if (data.deskripsi.length > 150) return null;
await Portofolio_funEditDataBisnis(data).then((res) => {
if (res.status === 200) {
setLoading(true);

View File

@@ -7,6 +7,7 @@ import {
Group,
Loader,
Paper,
ScrollArea,
SimpleGrid,
Stack,
Text,
@@ -24,32 +25,33 @@ import {
IconPencilPlus,
} from "@tabler/icons-react";
import { LIST_PORTOFOLIO } from "@/app_modules/model_global/portofolio";
import { MODEL_PORTOFOLIO_Lama } from "@/app_modules/model_global/portofolio";
import { useRouter } from "next/navigation";
import { RouterPortofolio } from "@/app/lib/router_hipmi/router_katalog";
import { Warna } from "@/app/lib/warna";
import { MODEL_PROFILE } from "../../profile/model/interface";
import { MODEL_PORTOFOLIO } from "../model/interface";
export default function ListPortofolioView({
listPorto,
profile,
userLoginId,
}: {
listPorto: LIST_PORTOFOLIO[];
listPorto: MODEL_PORTOFOLIO[];
profile: MODEL_PROFILE;
userLoginId: string;
}) {
const router = useRouter();
const [porto, setPorto] = useState(listPorto);
// const [porto, setPorto] = useState(listPorto);
const [loading, setLoading] = useState(false);
const [loadingPorto, setLoadingPorto] = useState(false);
const [idPorto, setIdPorto] = useState("")
const [idPorto, setIdPorto] = useState("");
return (
<>
{/* <pre>{JSON.stringify(porto, null, 2)}</pre> */}
<Paper p={"md"} shadow="lg" withBorder bg={"gray.1"}>
<Stack spacing={"lg"}>
<Stack spacing={"sm"}>
<Group position="apart">
<ActionIcon variant="transparent" disabled></ActionIcon>
<Title order={4}>Portofolio</Title>
@@ -68,55 +70,67 @@ export default function ListPortofolioView({
<ActionIcon variant="transparent" disabled></ActionIcon>
)}
</Group>
<Box>
{_.isEmpty(porto) ? (
<Center>
<Text fs={"italic"} fz={"xs"}>
- Belum Ada Portofolio -
</Text>
</Center>
) : (
<SimpleGrid
cols={4}
spacing="md"
breakpoints={[
{ maxWidth: "md", cols: 3, spacing: "md" },
{ maxWidth: "sm", cols: 2, spacing: "sm" },
{ maxWidth: "xs", cols: 1, spacing: "sm" },
]}
>
{porto.map((e) => (
<Paper
shadow="md"
key={e.id}
bg={"gray.5"}
radius={"md"}
onClick={() => {
setIdPorto(e.id)
setLoadingPorto(true);
router.push(`/dev/portofolio/main/${e.id}/`);
}}
>
<Grid align="center" p={"sm"}>
<Grid.Col span={"auto"}>
<Text fw={"bold"} lineClamp={1}>
{e.namaBisnis}
</Text>
</Grid.Col>
<Grid.Col span={"content"}>
<Stack>
{idPorto === e.id && loadingPorto ? (
<Loader color="gray" size={25}/>
) : (
<IconCaretRight color="black" size={25} />
)}
</Stack>
</Grid.Col>
</Grid>
</Paper>
))}
</SimpleGrid>
)}
<Box
h={
_.isEmpty(listPorto)
? 50
: listPorto.length === 1
? 100
: listPorto.length === 2
? 150
: 200
}
>
<ScrollArea h={"100%"} scrollbarSize={10}>
{_.isEmpty(listPorto) ? (
<Center>
<Text fs={"italic"} fz={"xs"} c={"gray"}>
- Belum Ada Portofolio -
</Text>
</Center>
) : (
<SimpleGrid
cols={4}
spacing="md"
breakpoints={[
{ maxWidth: "md", cols: 3, spacing: "md" },
{ maxWidth: "sm", cols: 2, spacing: "sm" },
{ maxWidth: "xs", cols: 1, spacing: "sm" },
]}
>
{listPorto.map((e, i) => (
<Paper
shadow="sm"
key={i}
bg={"gray.5"}
radius={"md"}
onClick={() => {
setIdPorto(e?.id);
setLoadingPorto(true);
router.push(`/dev/portofolio/main/${e?.id}/`);
}}
>
<Grid align="center" p={"sm"}>
<Grid.Col span={"auto"}>
<Text fw={"bold"} lineClamp={1}>
{e?.namaBisnis}
</Text>
</Grid.Col>
<Grid.Col span={"content"}>
<Stack>
{idPorto === e?.id && loadingPorto ? (
<Loader color="gray" size={25} />
) : (
<IconCaretRight color="black" size={25} />
)}
</Stack>
</Grid.Col>
</Grid>
</Paper>
))}
</SimpleGrid>
)}
</ScrollArea>
</Box>
</Stack>
</Paper>

View File

@@ -185,16 +185,20 @@ export default function ViewPortofolio({
</Grid>
</Stack>
</Paper>
<Button
radius={"xl"}
bg={"red"}
color="red"
onClick={() => {
open();
}}
>
<IconTrash />
</Button>
{userLoginId === dataPorto.Profile.User.id ? (
<Button
radius={"xl"}
bg={"red"}
color="red"
onClick={() => {
open();
}}
>
<IconTrash />
</Button>
) : (
""
)}
</Stack>
<Modal opened={opened} onClose={close} centered withCloseButton={false}>
@@ -227,7 +231,7 @@ async function onDelete(
) {
await Portofolio_funDeletePortofolioById(dataPorto).then((res) => {
if (res.status === 200) {
setLoadingDel(true)
setLoadingDel(true);
ComponentGlobal_NotifikasiBerhasil(res.message);
router.push(RouterProfile.katalog + `${dataPorto.profileId}`);
} else {

View File

@@ -1,4 +1,6 @@
import { MODEL_USER } from "@/app_modules/home/model/interface";
import { MODEL_IMAGES } from "@/app_modules/model_global/interface";
import { MODEL_PROFILE } from "../../profile/model/interface";
export interface MODEL_PORTOFOLIO {
id: string;
@@ -13,6 +15,7 @@ export interface MODEL_PORTOFOLIO {
Logo: MODEL_IMAGES;
logoId: string;
Portofolio_MediaSosial: MODEL_PORTOFOLIO_MEDSOS
Profile: MODEL_PROFILE
}
export interface MODEL_PORTOFOLIO_BIDANG_BISNIS {

View File

@@ -34,6 +34,7 @@ import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
import { useForm } from "@mantine/form";
import { useTimeout } from "@mantine/hooks";
import { validRegex } from "../../component/regular_expressions";
export default function CreateProfile({ userId }: { userId: any }) {
const [filePP, setFilePP] = useState<File | null>(null);
@@ -210,7 +211,7 @@ export default function CreateProfile({ userId }: { userId: any }) {
label="Email"
placeholder="Contoh: User@gmail.com"
error={
value.email.length > 0 && !value.email.includes("@")
value.email.length > 0 && !value.email.match(validRegex)
? "Invalid email"
: ""
}
@@ -225,6 +226,7 @@ export default function CreateProfile({ userId }: { userId: any }) {
withAsterisk
label="Alamat"
placeholder="Alamat lengkap"
error={value.alamat.length > 100 ? "Max 100 karakter" : ""}
onChange={(val) => {
setValue({
...value,
@@ -232,6 +234,7 @@ export default function CreateProfile({ userId }: { userId: any }) {
});
}}
/>
<Select
withAsterisk
label="Jenis Kelamin"
@@ -247,6 +250,7 @@ export default function CreateProfile({ userId }: { userId: any }) {
});
}}
/>
<ButtonAction
value={value as any}
userId={userId}
@@ -283,8 +287,8 @@ function ButtonAction({
};
if (_.values(body).includes(""))
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data");
if (!body.email.includes("@"))
return ComponentGlobal_NotifikasiPeringatan("Invalid Email");
if (!body.email.match(validRegex)) return null;
if (body.alamat.length > 100) return null;
const gambarPP = new FormData();
gambarPP.append("filePP", filePP as any);

View File

@@ -17,6 +17,8 @@ import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/component_global/
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";
import { validRegex } from "../../component/regular_expressions";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/component_global/notif_global/notifikasi_peringatan";
export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
const router = useRouter();
@@ -29,7 +31,10 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
const body = dataProfile;
// console.log(body)
if (_.values(body).includes("")) return toast("Lengkapi data");
if (_.values(body).includes(""))
return ComponentGlobal_NotifikasiPeringatan("Lengkapi data");
if (!body.email.match(validRegex)) return null;
if (body.alamat.length > 100) return null;
await Profile_funEditById(body).then((res) => {
if (res.status === 200) {
@@ -100,7 +105,8 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
label="Email"
placeholder="email"
error={
dataProfile?.email?.length > 0 && !dataProfile?.email.includes("@")
dataProfile?.email?.length > 0 &&
!dataProfile?.email.match(validRegex)
? "Invalid email"
: ""
}
@@ -118,6 +124,7 @@ export default function EditProfile({ data }: { data: MODEL_PROFILE }) {
label="Alamat"
placeholder="alamat"
value={dataProfile.alamat}
error={dataProfile.alamat.length > 100 ? "Max 100 karakter" : ""}
onChange={(val) => {
setDataProfile({
...dataProfile,

View File

@@ -5,6 +5,8 @@ import { MODEL_PROFILE } from "../model/interface";
import _ from "lodash";
import { v4 } from "uuid";
import fs from "fs";
import { revalidatePath } from "next/cache";
import { RouterHome } from "@/app/lib/router_hipmi/router_home";
export default async function funCreateNewProfile(
req: MODEL_PROFILE,
@@ -22,6 +24,10 @@ export default async function funCreateNewProfile(
if (findEmail) return { status: 400, message: "Email telah digunakan" };
const gambarProfile: any = gambarPP.get("filePP");
if (gambarProfile === "null")
return { status: 400, message: "Lengkapi Foto Profile" };
const fileName = gambarProfile.name;
const fileExtension = _.lowerCase(gambarProfile.name.split(".").pop());
const fRandomName = v4(fileName) + "." + fileExtension;
@@ -42,6 +48,9 @@ export default async function funCreateNewProfile(
fs.writeFileSync(`./public/profile/foto/${uploadPP.url}`, uploadPP_Folder);
const gambarBackground: any = gambarBG.get("fileBG");
if (gambarBackground === "null")
return { status: 400, message: "Lengkapi Foto Background" };
const fileNameBG = gambarBackground.name;
const fileExtensionBG = _.lowerCase(gambarBackground.name.split(".").pop());
const fRandomNameBG = v4(fileNameBG) + "." + fileExtensionBG;
@@ -65,8 +74,6 @@ export default async function funCreateNewProfile(
uploadBG_Folder
);
const createProfile = await prisma.profile.create({
data: {
userId: body.userId,
@@ -80,6 +87,7 @@ export default async function funCreateNewProfile(
});
if (!createProfile) return { status: 400, message: "Gagal membuat profile" };
revalidatePath(RouterHome.main_home);
return {
status: 201,

View File

@@ -1,4 +1,4 @@
export interface LIST_PORTOFOLIO {
export interface MODEL_PORTOFOLIO_Lama {
id: string;
namaBisnis: string;
alamatKantor: string;

View File

@@ -0,0 +1,13 @@
"use client";
import { Center } from "@mantine/core";
export default function ComponentUserSearch_IsEmptyData({ text }: { text: string }) {
return (
<>
<Center h={"50vh"} fz={"sm"} c="gray" fw={"bold"} style={{ zIndex: 1 }}>
{text}
</Center>
</>
);
}

View File

@@ -1,11 +1,49 @@
"use server";
import prisma from "@/app/lib/prisma";
import { user_getOneUserId } from "@/app_modules/fun_global/get_user_token";
export async function UserSearch_getListUser() {
const data = await prisma.user.findMany({
export async function UserSearch_getListUser({ name }: { name: string }) {
const userLoginId = await user_getOneUserId();
if (name === "") {
const data = await prisma.user.findMany({
where: {
masterUserRoleId: "1",
NOT: {
id: userLoginId,
},
},
select: {
id: true,
username: true,
nomor: true,
active: true,
masterUserRoleId: true,
Profile: {
select: {
id: true,
name: true,
imagesId: true,
},
},
},
});
return data;
}
const getDataCari = await prisma.user.findMany({
where: {
masterUserRoleId: "1"
masterUserRoleId: "1",
Profile: {
name: {
contains: name,
mode: "insensitive",
},
},
NOT: {
id: userLoginId,
},
},
select: {
id: true,
@@ -13,14 +51,9 @@ export async function UserSearch_getListUser() {
nomor: true,
active: true,
masterUserRoleId: true,
Profile: {
select: {
id: true,
name: true,
imagesId: true,
},
},
Profile: true,
},
});
return data;
return getDataCari;
}

View File

@@ -14,7 +14,6 @@ export async function UserSearch_searchByName(name: string) {
},
},
},
take: 10,
select: {
id: true,
username: true,

View File

@@ -21,6 +21,10 @@ 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";
import { data } from "autoprefixer";
import { UserSearch_getListUser } from "../fun/get/get_list_user";
import _ from "lodash";
import ComponentUserSearch_IsEmptyData from "../component/is_empty_data";
export default function UserSearch_MainView({
listUser,
@@ -28,11 +32,13 @@ export default function UserSearch_MainView({
listUser: MODEL_USER[];
}) {
const router = useRouter();
const [user, setUser] = useState(listUser);
const [data, setData] = useState(listUser);
const [loading, setLoading] = useState(false);
async function onSearch(name: string) {
await UserSearch_searchByName(name).then((res) => setUser(res as any));
await UserSearch_getListUser({ name: name }).then((res) =>
setData(res as any)
);
}
// return (
@@ -43,75 +49,83 @@ export default function UserSearch_MainView({
// </>
// );
if(loading) return <ComponentGlobal_V2_LoadingPage/>
if (loading) return <ComponentGlobal_V2_LoadingPage />;
return (
<>
<Box>
{/* <pre>{JSON.stringify(user, null,2)}</pre>r */}
<Stack spacing={"md"}>
<TextInput
style={{ zIndex: 99 }}
pos={"sticky"}
top={"6vh"}
icon={<IconSearch size={20} />}
placeholder="Masukan nama pegguna"
onChange={(val) => onSearch(val.target.value)}
/>
{!user ? (
""
) : (
<Box>
{user?.map((e) =>
e.Profile === null ? (
""
) : (
<Stack key={e.id} spacing={"xs"} mt={"xs"}>
<Grid>
<Grid.Col span={2}>
<Center h={"100%"}>
<Avatar
sx={{ borderStyle: "solid", borderWidth: "0.5px" }}
radius={"xl"}
size={"md"}
src={
RouterProfile.api_foto_profile +
`${e?.Profile?.imagesId}`
}
/>
</Center>
</Grid.Col>
<Grid.Col span={"auto"}>
<Stack spacing={0}>
<Text fw={"bold"} lineClamp={1}>
{e?.Profile?.name}
</Text>
<Text fz={"sm"} fs={"italic"}>
+{e?.nomor}
</Text>
</Stack>
</Grid.Col>
<Grid.Col span={2}>
<Center h={"100%"}>
<ActionIcon
variant="transparent"
onClick={() => {
setLoading(true);
router.push(
RouterProfile.katalog + `${e?.Profile?.id}`
);
}}
>
<IconChevronRight />
</ActionIcon>
</Center>
</Grid.Col>
</Grid>
<Divider />
</Stack>
)
)}
</Box>
)}
<Box>
{_.isEmpty(data) ? (
<ComponentUserSearch_IsEmptyData text="Tidak ada pengguna" />
) : (
<Box>
{data?.map((e, i) =>
e?.Profile === null ? (
""
) : (
<Stack key={i} spacing={"xs"} mt={"xs"}>
<Grid>
<Grid.Col span={2}>
<Center h={"100%"}>
<Avatar
sx={{
borderStyle: "solid",
borderWidth: "0.5px",
}}
radius={"xl"}
size={"md"}
src={
RouterProfile?.api_foto_profile +
`${e?.Profile?.imagesId}`
}
/>
</Center>
</Grid.Col>
<Grid.Col span={"auto"}>
<Stack spacing={0}>
<Text fw={"bold"} lineClamp={1}>
{e?.Profile?.name}
</Text>
<Text fz={"sm"} fs={"italic"}>
+{e?.nomor}
</Text>
</Stack>
</Grid.Col>
<Grid.Col span={2}>
<Center h={"100%"}>
<ActionIcon
variant="transparent"
onClick={() => {
setLoading(true);
router.push(
RouterProfile.katalog + `${e?.Profile?.id}`
);
}}
>
<IconChevronRight />
</ActionIcon>
</Center>
</Grid.Col>
</Grid>
<Divider />
</Stack>
)
)}
</Box>
)}
</Box>
</Stack>
</Box>
{/* <pre>{JSON.stringify(data, null, 2)}</pre> */}
</>
);
}

View File

@@ -60,6 +60,13 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.7.2":
version "7.24.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c"
integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/types@^7.22.15":
version "7.23.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002"
@@ -1032,6 +1039,14 @@
dependencies:
"@types/react" "*"
"@types/react-virtualized@^9.21.30":
version "9.21.30"
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.30.tgz#ba39821bcb2487512a8a2cdd9fbdb5e6fc87fedb"
integrity sha512-4l2TFLQ8BCjNDQlvH85tU6gctuZoEdgYzENQyZHpgTHU7hoLzYgPSOALMAeA58LOWua8AzC6wBivPj1lfl6JgQ==
dependencies:
"@types/prop-types" "*"
"@types/react" "*"
"@types/react@*":
version "18.2.57"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.57.tgz#147b516d8bdb2900219acbfc6f939bdeecca7691"
@@ -1565,7 +1580,7 @@ clsx@1.1.1:
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
clsx@^1.1.1:
clsx@^1.0.4, clsx@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
@@ -1784,7 +1799,7 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-helpers@^5.0.1:
dom-helpers@^5.0.1, dom-helpers@^5.1.3:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
@@ -3884,6 +3899,13 @@ react-icons@^5.0.1:
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.0.1.tgz#1694e11bfa2a2888cab47dcc30154ce90485feee"
integrity sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==
react-infinite-scroll-component@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz#7e511e7aa0f728ac3e51f64a38a6079ac522407f"
integrity sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==
dependencies:
throttle-debounce "^2.1.0"
react-international-phone@^4.2.6:
version "4.2.6"
resolved "https://registry.yarnpkg.com/react-international-phone/-/react-international-phone-4.2.6.tgz#a92518b66b44015f5e32c96b646e0355056ae809"
@@ -3894,6 +3916,11 @@ react-is@^16.13.1, react-is@^16.7.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-property@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.0.tgz#2156ba9d85fa4741faf1918b38efc1eae3c6a136"
@@ -3976,6 +4003,18 @@ react-transition-group@4.4.2:
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-virtualized@^9.22.5:
version "9.22.5"
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.5.tgz#bfb96fed519de378b50d8c0064b92994b3b91620"
integrity sha512-YqQMRzlVANBv1L/7r63OHa2b0ZsAaDp1UhVNEdUaXI8A5u6hTpA5NYtUueLH2rFuY/27mTGIBl7ZhqFKzw18YQ==
dependencies:
"@babel/runtime" "^7.7.2"
clsx "^1.0.4"
dom-helpers "^5.1.3"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-lifecycles-compat "^3.0.4"
react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
@@ -4494,6 +4533,11 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
throttle-debounce@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2"
integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==
throttle-debounce@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb"