perbaikan(kolaborasi): memperbaiki bug modul kolaborasi dan tingkatkan komponen UI

Deskripsi:

- Perbaikan endpoint API dan routing kolaborasi
- Pembaruan tampilan grup kolaborasi dan partisipasi proyek
- Peningkatan komponen skeleton loading
- Perbaikan tampilan komponen avatar dan username
- Refaktor layout pembuatan dan detail kolaborasi
This commit is contained in:
2025-01-02 14:42:49 +08:00
parent ea2e52937c
commit d0def08ff6
26 changed files with 981 additions and 459 deletions

View File

@@ -1,4 +1,5 @@
import { prisma } from "@/app/lib"; import { prisma } from "@/app/lib";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import backendLogger from "@/util/backendLogger"; import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
@@ -11,36 +12,87 @@ export async function GET(
try { try {
let fixData; let fixData;
const { id } = context.params; const { id } = context.params;
const { searchParams } = new URL(request.url);
const kategori = searchParams.get("kategori");
const page = searchParams.get("page");
const takeData = 10;
const dataSkip = Number(page) * takeData - takeData;
// Buatkan api untuk list partisipasi // Buatkan api untuk list partisipasi
fixData = await prisma.projectCollaboration.findFirst({ const userLoginId = await funGetUserIdByToken();
where: {
id: id, if (userLoginId == null) {
}, return NextResponse.json(
select: { {
id: true, success: false,
isActive: true, message: "Gagal mendapatkan data, user id tidak ada",
title: true, },
lokasi: true, { status: 500 }
purpose: true, );
benefit: true, }
createdAt: true,
// jumlah_partisipan: true, if (kategori == "detail") {
Author: { fixData = await prisma.projectCollaboration.findFirst({
select: { where: {
id: true, id: id,
Profile: true, },
select: {
id: true,
isActive: true,
title: true,
lokasi: true,
purpose: true,
benefit: true,
createdAt: true,
// jumlah_partisipan: true,
Author: {
select: {
id: true,
Profile: true,
},
},
ProjectCollaborationMaster_Industri: true,
ProjectCollaboration_Partisipasi: {
where: {
isActive: true,
},
}, },
}, },
ProjectCollaborationMaster_Industri: true, });
ProjectCollaboration_Partisipasi: { } else if (kategori == "list_partisipan") {
where: { fixData = await prisma.projectCollaboration_Partisipasi.findMany({
isActive: true, take: takeData,
}, skip: dataSkip,
where: {
projectCollaborationId: id,
isActive: true,
}, },
}, select: {
}); id: true,
User: {
select: {
id: true,
Profile: true,
},
},
deskripsi_diri: true,
},
});
} else if (kategori == "cek_partisipasi") {
const cek = await prisma.projectCollaboration_Partisipasi.findFirst({
where: {
projectCollaborationId: id,
userId: userLoginId,
},
});
if (cek === null) {
fixData = false;
} else {
fixData = true;
}
}
return NextResponse.json( return NextResponse.json(
{ success: true, message: "Berhasil mendapatkan data", data: fixData }, { success: true, message: "Berhasil mendapatkan data", data: fixData },

View File

@@ -0,0 +1,82 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server";
export const dynamic = "force-dynamic";
export async function GET(
request: Request,
context: { params: { id: string } }
) {
try {
let fixData;
const { id } = context.params;
const { searchParams } = new URL(request.url);
const kategori = searchParams.get("kategori");
const page = searchParams.get("page");
const takeData = 10;
const skipData = Number(page) * takeData - takeData;
// data room { id, grup_name}
if (kategori == "detail") {
fixData = await prisma.projectCollaboration_RoomChat.findFirst({
where: {
id: id,
},
select: {
id: true,
name: true,
},
});
} else if (kategori == "info_group") {
fixData = await prisma.projectCollaboration_RoomChat.findFirst({
where: {
id: id,
},
select: {
id: true,
name: true,
ProjectCollaboration: {
select: {
id: true,
isActive: true,
title: true,
lokasi: true,
purpose: true,
benefit: true,
createdAt: true,
ProjectCollaborationMaster_Industri: true,
},
},
ProjectCollaboration_AnggotaRoomChat: {
select: {
User: {
select: {
id: true,
Profile: {
select: {
id: true,
name: true,
imageId: true,
},
},
},
},
},
},
},
});
}
return NextResponse.json(
{ success: true, message: "Berhasil mendapatkan data", data: fixData },
{ status: 200 }
);
} catch (error) {
backendLogger.error("Gagal mendapatkan data", error);
return NextResponse.json(
{ success: false, message: "Gagal mendapatkan data" },
{ status: 500 }
);
}
}

View File

@@ -15,6 +15,8 @@ export default async function Page({ params }: { params: { id: string } }) {
"ProjectCollaboration", "ProjectCollaboration",
"ProjectCollaboration_AnggotaRoomChat", "ProjectCollaboration_AnggotaRoomChat",
]); ]);
let listMsg = await colab_getMessageByRoomId({ roomId: roomId, page: 1 }); let listMsg = await colab_getMessageByRoomId({ roomId: roomId, page: 1 });
const dataUserLogin = await user_getOneByUserId(userLoginId as string); const dataUserLogin = await user_getOneByUserId(userLoginId as string);

View File

@@ -1,14 +1,9 @@
import prisma from "@/app/lib/prisma";
import { Colab_DetailInfoGrup } from "@/app_modules/colab"; import { Colab_DetailInfoGrup } from "@/app_modules/colab";
import colab_getListAnggotaByRoomId from "@/app_modules/colab/fun/get/room_chat/get_list_anggota_by_room_id";
export default async function Page({ params }: { params: { id: string } }) {
let roomId = params.id;
const dataRoom = await colab_getListAnggotaByRoomId(roomId);
export default async function Page() {
return ( return (
<> <>
<Colab_DetailInfoGrup dataRoom={dataRoom as any} /> <Colab_DetailInfoGrup />
</> </>
); );
} }

View File

@@ -1,24 +1,13 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get"; import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { Colab_MainDetail } from "@/app_modules/colab"; import { Colab_MainDetail } from "@/app_modules/colab";
import colab_funCekPartisipasiById from "@/app_modules/colab/fun/get/cek_partisipasi_by_user_id";
import colab_getListPartisipanByColabId from "@/app_modules/colab/fun/get/get_list_partisipan_by_id";
import colab_getOneCollaborationById from "@/app_modules/colab/fun/get/get_one_by_id";
export default async function Page({ params }: { params: { id: string } }) { export default async function Page() {
let colabId = params.id;
const userLoginId = await funGetUserIdByToken(); const userLoginId = await funGetUserIdByToken();
const dataColab = await colab_getOneCollaborationById(colabId);
const listPartisipan = await colab_getListPartisipanByColabId(colabId);
const cekPartisipan = await colab_funCekPartisipasiById(colabId);
return ( return (
<> <>
<Colab_MainDetail <Colab_MainDetail
dataColab={{} as any}
userLoginId={userLoginId as string} userLoginId={userLoginId as string}
listPartisipan={listPartisipan as any}
cekPartisipan={cekPartisipan}
/> />
</> </>
); );

View File

@@ -3,7 +3,9 @@ import { LayoutColab_DetailPartisipasiProyek } from "@/app_modules/colab";
export default async function Layout({ children }: { children: any }) { export default async function Layout({ children }: { children: any }) {
return ( return (
<> <>
<LayoutColab_DetailPartisipasiProyek>{children}</LayoutColab_DetailPartisipasiProyek> <LayoutColab_DetailPartisipasiProyek>
{children}
</LayoutColab_DetailPartisipasiProyek>
</> </>
); );
} }

View File

@@ -1,18 +1,9 @@
import { Colab_DetailPartisipasiProyek } from "@/app_modules/colab"; import { Colab_DetailPartisipasiProyek } from "@/app_modules/colab";
import colab_getListPartisipanByColabId from "@/app_modules/colab/fun/get/get_list_partisipan_by_id";
import colab_getOneCollaborationById from "@/app_modules/colab/fun/get/get_one_by_id";
export default async function Page({params}: {params: {id: string}}) {
const colabId = params.id
const dataColab = await colab_getOneCollaborationById(colabId)
const listPartisipan = await colab_getListPartisipanByColabId(colabId)
export default async function Page() {
return ( return (
<> <>
<Colab_DetailPartisipasiProyek <Colab_DetailPartisipasiProyek />
dataColab={dataColab as any}
listPartisipan={listPartisipan as any}
/>
</> </>
); );
} }

View File

@@ -3,19 +3,12 @@ import React from "react";
export default async function Layout({ export default async function Layout({
children, children,
params,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
params: { id: string };
}) { }) {
let colabId = params.id;
return ( return (
<> <>
<LayoutColab_DetailProyekSaya colabId={colabId}> <LayoutColab_DetailProyekSaya>{children}</LayoutColab_DetailProyekSaya>
{children}
</LayoutColab_DetailProyekSaya>
</> </>
); );
} }

View File

@@ -1,19 +1,9 @@
import { Colab_DetailProyekSaya } from "@/app_modules/colab"; import { Colab_DetailProyekSaya } from "@/app_modules/colab";
import colab_getListPartisipanByColabId from "@/app_modules/colab/fun/get/get_list_partisipan_by_id";
import colab_getOneCollaborationById from "@/app_modules/colab/fun/get/get_one_by_id";
export default async function Page({ params }: { params: { id: string } }) {
const colabId = params.id;
const dataColab = await colab_getOneCollaborationById(colabId);
const listPartisipan = await colab_getListPartisipanByColabId(colabId);
export default async function Page() {
return ( return (
<> <>
{/* <pre>{JSON.stringify(listPartisipan, null,2)}</pre> */} <Colab_DetailProyekSaya />
<Colab_DetailProyekSaya
dataColab={dataColab as any}
listPartisipan={listPartisipan as any}
/>
</> </>
); );
} }

View File

@@ -5,7 +5,7 @@ import {
UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutHeaderTamplate,
UIGlobal_LayoutTamplate, UIGlobal_LayoutTamplate,
} from "@/app_modules/_global/ui"; } from "@/app_modules/_global/ui";
import { Center, Grid, Group, Skeleton, Stack } from "@mantine/core"; import { Grid, Skeleton, Stack } from "@mantine/core";
export default function Voting_ComponentSkeletonViewPuh() { export default function Voting_ComponentSkeletonViewPuh() {
return ( return (
@@ -15,6 +15,23 @@ export default function Voting_ComponentSkeletonViewPuh() {
> >
<Stack> <Stack>
<ComponentGlobal_CardStyles marginBottom={"0"}> <ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack>
<Skeleton h={20} w={100} />
{Array.from(new Array(2)).map((e, i) => (
<Grid align="center" gutter={"md"} key={i}>
<Grid.Col span={"content"}>
<Skeleton circle height={40} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={150} />
</Grid.Col>
</Grid>
))}
</Stack>
</ComponentGlobal_CardStyles>
{/* <ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack spacing={"xl"}> <Stack spacing={"xl"}>
<Grid align="center" gutter={"md"}> <Grid align="center" gutter={"md"}>
<Grid.Col span={"content"}> <Grid.Col span={"content"}>
@@ -23,9 +40,6 @@ export default function Voting_ComponentSkeletonViewPuh() {
<Grid.Col span={3}> <Grid.Col span={3}>
<Skeleton height={20} w={150} /> <Skeleton height={20} w={150} />
</Grid.Col> </Grid.Col>
{/* <Grid.Col span={3} offset={3}>
<Skeleton height={20} w={150} />
</Grid.Col> */}
</Grid> </Grid>
<Center> <Center>
<Skeleton height={15} w={200} /> <Skeleton height={15} w={200} />
@@ -54,7 +68,7 @@ export default function Voting_ComponentSkeletonViewPuh() {
<Skeleton height={15} w={100} /> <Skeleton height={15} w={100} />
<Skeleton height={15} w={"100%"} /> <Skeleton height={15} w={"100%"} />
</Stack> </Stack>
</ComponentGlobal_CardStyles> </ComponentGlobal_CardStyles> */}
{/* <ComponentGlobal_CardStyles> {/* <ComponentGlobal_CardStyles>
<Stack> <Stack>

View File

@@ -63,7 +63,7 @@ export function ComponentGlobal_AvatarAndUsername({
<Text <Text
c={MainColor.white} c={MainColor.white}
fw={"bold"} fw={"bold"}
fz={fontSize ? fontSize : "sm"} fz={fontSize ? fontSize : "md"}
lineClamp={1} lineClamp={1}
onClick={() => onCheckProfile()} onClick={() => onCheckProfile()}
> >

View File

@@ -2,6 +2,20 @@ import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { Card } from "@mantine/core"; import { Card } from "@mantine/core";
import React from "react"; import React from "react";
/**
* ComponentGlobal_CardStyles
*
* A React component that renders a customizable card element.
*
* Props:
* - children (React.ReactNode): Content to be displayed inside the card.
* - backgroundColor (string, optional): Background color of the card. Defaults to AccentColor.darkblue.
* - border (string, optional): Border color of the card. Defaults to AccentColor.blue.
* - marginBottom (string | number, optional): Margin below the card. Defaults to "15px".
* - height (string | number, optional): Height of the card. Defaults to "auto".
* - color (string, optional): Text color inside the card. Defaults to MainColor.white.
* - onClickHandler (React.MouseEventHandler<HTMLDivElement>, optional): Function to handle click events on the card.
*/
export function ComponentGlobal_CardStyles({ export function ComponentGlobal_CardStyles({
children, children,
backgroundColor, backgroundColor,

View File

@@ -11,7 +11,33 @@ export const apiGetAllCollaboration = async ({
return await respone.json().catch(() => null); return await respone.json().catch(() => null);
}; };
export const apiGetOneCollaborationById = async ({ id }: { id: string }) => { export const apiGetOneCollaborationById = async ({
const respone = await fetch(`/api/collaboration/${id}`); id,
kategori,
page,
}: {
id: string;
kategori: "detail" | "list_partisipan" | "cek_partisipasi";
page?: string;
}) => {
const respone = await fetch(
`/api/collaboration/${id}?kategori=${kategori}&page=${page}`
);
return await respone.json().catch(() => null); return await respone.json().catch(() => null);
}; };
export const apiGetDataGroupById = async ({
id,
kategori,
page,
}: {
id: string;
kategori: "detail" | "info_group"
page?: string;
}) => {
const respone = await fetch(
`/api/collaboration/group/${id}?kategori=${kategori}&page=${page}`
);
return await respone.json().catch(() => null)
}

View File

@@ -19,15 +19,15 @@ export default function ComponentColab_DetailData({
<Stack spacing={"sm"}> <Stack spacing={"sm"}>
<Grid> <Grid>
<Grid.Col span={2}> <Grid.Col span={2}>
<Text fw={"bold"} fz={"sm"}> <Text fw={"bold"} >
Industri Industri
</Text> </Text>
</Grid.Col> </Grid.Col>
<Grid.Col span={1}> <Grid.Col span={1}>
<Text fz={"sm"}>:</Text> <Text >:</Text>
</Grid.Col> </Grid.Col>
<Grid.Col span={"auto"}> <Grid.Col span={"auto"}>
<Text fz={"sm"}> <Text >
{data?.ProjectCollaborationMaster_Industri.name {data?.ProjectCollaborationMaster_Industri.name
? data.ProjectCollaborationMaster_Industri.name ? data.ProjectCollaborationMaster_Industri.name
: "Industri"} : "Industri"}
@@ -37,31 +37,31 @@ export default function ComponentColab_DetailData({
<Grid> <Grid>
<Grid.Col span={2}> <Grid.Col span={2}>
<Text fw={"bold"} fz={"sm"}> <Text fw={"bold"} >
Lokasi Lokasi
</Text> </Text>
</Grid.Col> </Grid.Col>
<Grid.Col span={1}> <Grid.Col span={1}>
<Text fz={"sm"}>:</Text> <Text >:</Text>
</Grid.Col> </Grid.Col>
<Grid.Col span={"auto"}> <Grid.Col span={"auto"}>
<Text fz={"sm"} lineClamp={1}> <Text lineClamp={1}>
{data?.lokasi ? data.lokasi : " Lokasi dari proyek"} {data?.lokasi ? data.lokasi : " Lokasi dari proyek"}
</Text> </Text>
</Grid.Col> </Grid.Col>
</Grid> </Grid>
<Stack spacing={5}> <Stack spacing={5}>
<Text fw={"bold"} fz={"sm"}> <Text fw={"bold"} >
Tujuan proyek Tujuan proyek
</Text> </Text>
<Text fz={"sm"}>{data?.purpose ? data?.purpose : "-"}</Text> <Text >{data?.purpose ? data?.purpose : "-"}</Text>
</Stack> </Stack>
<Stack spacing={5}> <Stack spacing={5}>
<Text fw={"bold"} fz={"sm"}> <Text fw={"bold"} >
Keuntungan Keuntungan
</Text> </Text>
<Text fz={"sm"}>{data?.benefit ? data?.benefit : "-"}</Text> <Text >{data?.benefit ? data?.benefit : "-"}</Text>
</Stack> </Stack>
</Stack> </Stack>
</Box> </Box>

View File

@@ -4,9 +4,14 @@ import {
AccentColor, AccentColor,
MainColor, MainColor,
} from "@/app_modules/_global/color/color_pallet"; } from "@/app_modules/_global/color/color_pallet";
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown"; import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown";
import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil"; import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal"; import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal";
import notifikasiToUser_funCreate from "@/app_modules/notifikasi/fun/create/create_notif_to_user";
import { clientLogger } from "@/util/clientLogger";
import mqtt_client from "@/util/mqtt_client";
import { import {
ActionIcon, ActionIcon,
Box, Box,
@@ -14,86 +19,219 @@ import {
Center, Center,
Drawer, Drawer,
Group, Group,
Paper, Loader,
ScrollArea,
Stack, Stack,
Text, Text,
Textarea, Textarea,
Title, Title,
} from "@mantine/core"; } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks"; import { useDisclosure, useShallowEffect } from "@mantine/hooks";
import { IconX } from "@tabler/icons-react"; import { IconX } from "@tabler/icons-react";
import _ from "lodash";
import { ScrollOnly } from "next-scroll-loader";
import { useParams } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { apiGetOneCollaborationById } from "../../_lib/api_collaboration";
import colab_funCreatePartisipan from "../../fun/create/fun_create_partisipan_by_user_id"; import colab_funCreatePartisipan from "../../fun/create/fun_create_partisipan_by_user_id";
import colab_getListPartisipanByColabId from "../../fun/get/get_list_partisipan_by_id";
import { MODEL_COLLABORATION_PARTISIPASI } from "../../model/interface"; import { MODEL_COLLABORATION_PARTISIPASI } from "../../model/interface";
import { Collaboration_SkeletonListPrtisipanIsUser } from "../skeleton_view";
import ComponentColab_AuthorNameOnListPartisipan from "./header_author_list_partisipan"; import ComponentColab_AuthorNameOnListPartisipan from "./header_author_list_partisipan";
import notifikasiToUser_funCreate from "@/app_modules/notifikasi/fun/create/create_notif_to_user";
import mqtt_client from "@/util/mqtt_client";
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
export default function ComponentColab_DetailListPartisipasiUser({ export default function ComponentColab_DetailListPartisipasiUser({
listPartisipan,
userLoginId, userLoginId,
authorId, authorId,
colabId,
cekPartisipan,
}: { }: {
listPartisipan?: MODEL_COLLABORATION_PARTISIPASI[];
userLoginId?: string; userLoginId?: string;
authorId?: string; authorId?: string;
colabId?: string;
cekPartisipan?: boolean;
}) { }) {
const [apply, setApply] = useState(false); const params = useParams<{ id: string }>();
const [data, setData] = useState(listPartisipan); const [data, setData] = useState<MODEL_COLLABORATION_PARTISIPASI[] | null>(
null
);
const [isPartisipan, setCekPartisipan] = useState<boolean | null>(null);
const [activePage, setActivePage] = useState(1);
const [opened, { open, close }] = useDisclosure(false); const [opened, { open, close }] = useDisclosure(false);
const [deskripsi, setDeskripsi] = useState(""); const [deskripsi, setDeskripsi] = useState("");
const [isLoading, setIsLoading] = useState(false);
useShallowEffect(() => {
onLoadDataPartisipan();
}, []);
async function onLoadDataPartisipan() {
async function onJoin() { try {
const res = await colab_funCreatePartisipan( const respone = await apiGetOneCollaborationById({
colabId as any, id: params.id,
userLoginId as any, kategori: "list_partisipan",
deskripsi page: `${activePage}`,
);
if (res.status === 201) {
const dataNotif = {
appId: res?.data?.ProjectCollaboration?.id,
userId: res?.data?.ProjectCollaboration?.userId,
pesan: res?.data?.ProjectCollaboration?.title,
status: "Partisipan Project",
kategoriApp: "COLLABORATION",
title: "Partisipan baru telah bergabung !",
};
const createNotifikasi = await notifikasiToUser_funCreate({
data: dataNotif as any,
}); });
if (createNotifikasi.status === 201) { if (respone) {
mqtt_client.publish( setData(respone.data);
"USER",
JSON.stringify({
userId: dataNotif.userId,
count: 1,
})
);
} }
} catch (error) {
const resList = await colab_getListPartisipanByColabId(colabId as any); clientLogger.error("Error get list partisipan", error);
setApply(true);
close();
setData(resList as any);
ComponentGlobal_NotifikasiBerhasil(res.message);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
} }
} }
useShallowEffect(() => {
onCheckPartisipasi();
}, []);
async function onCheckPartisipasi() {
try {
const respone = await apiGetOneCollaborationById({
id: params.id,
kategori: "cek_partisipasi",
});
if (respone) {
setCekPartisipan(respone.data);
}
} catch (error) {
clientLogger.error("Error cek partisipasi", error);
}
}
async function onJoin() {
try {
setIsLoading(true);
const res = await colab_funCreatePartisipan({
id: params.id,
deskripsi: deskripsi,
});
if (res.status === 201) {
// const dataNotif = {
// appId: res?.data?.ProjectCollaboration?.id,
// userId: res?.data?.ProjectCollaboration?.userId,
// pesan: res?.data?.ProjectCollaboration?.title,
// status: "Partisipan Project",
// kategoriApp: "COLLABORATION",
// title: "Partisipan baru telah bergabung !",
// };
// const createNotifikasi = await notifikasiToUser_funCreate({
// data: dataNotif as any,
// });
// if (createNotifikasi.status === 201) {
// mqtt_client.publish(
// "USER",
// JSON.stringify({
// userId: dataNotif.userId,
// count: 1,
// })
// );
// }
const respone = await apiGetOneCollaborationById({
id: params.id,
kategori: "list_partisipan",
page: `${activePage}`,
});
if (respone) {
setData(respone.data);
}
const cekPartisipan = await apiGetOneCollaborationById({
id: params.id,
kategori: "cek_partisipasi",
});
if (cekPartisipan) {
setCekPartisipan(cekPartisipan);
}
close();
ComponentGlobal_NotifikasiBerhasil(res.message);
} else {
ComponentGlobal_NotifikasiGagal(res.message);
}
} catch (error) {
clientLogger.error("Error create partisipan", error);
} finally {
setIsLoading(false);
}
}
if (_.isNull(data) || _.isNull(isPartisipan)) {
return <Collaboration_SkeletonListPrtisipanIsUser />;
}
return ( return (
<> <>
<Stack>
{userLoginId !== authorId && (
<Center>
<Button
radius={"xl"}
disabled={isPartisipan}
color={isPartisipan ? "green" : "yellow"}
onClick={open}
// bg={MainColor.yellow}
>
{isPartisipan ? "Telah Berpartisipasi" : "Partisipasi"}
</Button>
</Center>
)}
{_.isEmpty(data) ? (
<ComponentGlobal_CardStyles>
<Stack>
<Center>
<Title order={5}>Partispasi User ({data?.length})</Title>
</Center>
<ComponentGlobal_IsEmptyData
height={10}
text=" Tidak ada partisipan"
/>
</Stack>
</ComponentGlobal_CardStyles>
) : (
<ComponentGlobal_CardStyles>
<Stack spacing={"xl"}>
<Center>
<Title order={5}>Partispasi User ({data?.length})</Title>
</Center>{" "}
<Box>
<ScrollOnly
height="50vh"
renderLoading={() => (
<Center mt={"lg"}>
<Loader color={"yellow"} />
</Center>
)}
data={data}
setData={setData as any}
moreData={async () => {
const respone = await apiGetOneCollaborationById({
id: params.id,
kategori: "list_partisipan",
page: `${activePage + 1}`,
});
setActivePage((val) => val + 1);
return respone.data;
}}
>
{(item) => (
<ComponentColab_AuthorNameOnListPartisipan
isPembatas={true}
author={item.User}
deskripsi={item.deskripsi_diri}
/>
)}
</ScrollOnly>
</Box>
</Stack>
</ComponentGlobal_CardStyles>
)}
</Stack>
<Drawer <Drawer
opened={opened} opened={opened}
onClose={close} onClose={close}
@@ -149,6 +287,8 @@ export default function ComponentColab_DetailListPartisipasiUser({
maxInput={300} maxInput={300}
/> />
<Button <Button
loaderPosition="center"
loading={isLoading}
disabled={!deskripsi} disabled={!deskripsi}
radius={"xl"} radius={"xl"}
color="yellow" color="yellow"
@@ -163,55 +303,6 @@ export default function ComponentColab_DetailListPartisipasiUser({
</Group> </Group>
</Stack> </Stack>
</Drawer> </Drawer>
<Stack>
{userLoginId !== authorId ? (
<Center>
<Button
radius={"xl"}
disabled={cekPartisipan ? true : false}
color={cekPartisipan ? "green" : "yellow"}
onClick={open}
// bg={MainColor.yellow}
>
{cekPartisipan ? "Telah Berpartisipasi" : "Partisipasi"}
</Button>
</Center>
) : (
""
)}
<ComponentGlobal_CardStyles>
<Stack spacing={"xl"}>
<Center>
<Title order={5}>Partispasi User ({data?.length})</Title>
</Center>{" "}
<ScrollArea h={data?.length === 0 ? 30 : 400}>
<Box>
<Stack>
{data?.length === 0 ? (
<Center>
<Text fz={"xs"} fw={"bold"} c={"gray"}>
Tidak ada partisipan
</Text>
</Center>
) : (
data?.map((e, i) => (
<Box key={i}>
<ComponentColab_AuthorNameOnListPartisipan
isPembatas={true}
author={e.User}
deskripsi={e.deskripsi_diri}
/>
</Box>
))
)}
</Stack>
</Box>
</ScrollArea>
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</> </>
); );
} }

View File

@@ -3,6 +3,8 @@
import { ComponentGlobal_AvatarAndUsername } from "@/app_modules/_global/component"; import { ComponentGlobal_AvatarAndUsername } from "@/app_modules/_global/component";
import { Group, Stack, Text } from "@mantine/core"; import { Group, Stack, Text } from "@mantine/core";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import moment from "moment";
import "moment/locale/id";
export default function ComponentColab_AuthorNameOnHeader({ export default function ComponentColab_AuthorNameOnHeader({
tglPublish, tglPublish,
@@ -19,10 +21,8 @@ export default function ComponentColab_AuthorNameOnHeader({
component={ component={
<Group position="right"> <Group position="right">
{tglPublish ? ( {tglPublish ? (
<Text fz={"xs"}> <Text lineClamp={1}>
{new Intl.DateTimeFormat("id-ID", { {moment(tglPublish).locale("id").format("ll")}
dateStyle: "medium",
}).format(tglPublish)}
</Text> </Text>
) : ( ) : (
"" ""
@@ -65,7 +65,7 @@ export default function ComponentColab_AuthorNameOnHeader({
<Grid.Col span={"content"}> <Grid.Col span={"content"}>
<Stack justify="center" h={"100%"}> <Stack justify="center" h={"100%"}>
{tglPublish ? ( {tglPublish ? (
<Text fz={"xs"}> <Text >
{new Intl.DateTimeFormat("id-ID", { {new Intl.DateTimeFormat("id-ID", {
dateStyle: "medium" dateStyle: "medium"

View File

@@ -1,30 +1,38 @@
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component"; import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { Center, Grid, Skeleton, Stack } from "@mantine/core"; import { Center, Grid, Group, Skeleton, Stack } from "@mantine/core";
export { export {
Collaboration_SkeletonCreate,
Collaboration_SkeletonBeranda, Collaboration_SkeletonBeranda,
Collaboration_SkeletonCreate,
Collaboration_SkeletonDetail,
Collaboration_SkeletonDetailInfoGroup,
Collaboration_SkeletonGrup, Collaboration_SkeletonGrup,
Collaboration_SkeletonListPartisipan,
Collaboration_SkeletonListPrtisipanIsUser,
}; };
function Collaboration_SkeletonCreate() { function Collaboration_SkeletonCreate() {
return ( return (
<> <>
<Stack px={"xl"} spacing={"lg"}> <Stack px={"xl"} spacing={"md"}>
<Stack spacing={"xs"}> <Stack spacing={"xs"}>
<Skeleton height={10} width={50} /> <Skeleton height={15} width={50} />
<Skeleton height={40} /> <Skeleton height={40} />
</Stack> </Stack>
<Stack spacing={"xs"}> <Stack spacing={"xs"}>
<Skeleton height={10} width={50} /> <Skeleton height={15} width={50} />
<Skeleton height={40} /> <Skeleton height={40} />
</Stack> </Stack>
<Stack spacing={"xs"}> <Stack spacing={"xs"}>
<Skeleton height={10} width={50} /> <Skeleton height={15} width={50} />
<Skeleton height={40} />
</Stack>
<Stack spacing={"xs"}>
<Skeleton height={15} width={50} />
<Skeleton height={130} /> <Skeleton height={130} />
</Stack> </Stack>
<Stack spacing={"xs"}> <Stack spacing={"xs"}>
<Skeleton height={10} width={50} /> <Skeleton height={15} width={50} />
<Skeleton height={130} /> <Skeleton height={130} />
</Stack> </Stack>
@@ -94,9 +102,176 @@ function Collaboration_SkeletonGrup() {
<> <>
{Array.from(new Array(2)).map((e, i) => ( {Array.from(new Array(2)).map((e, i) => (
<ComponentGlobal_CardStyles marginBottom={"15px"} key={i}> <ComponentGlobal_CardStyles marginBottom={"15px"} key={i}>
<Skeleton h={40} /> <Group position="apart">
<Stack>
<Skeleton h={15} w={100} />
<Skeleton h={15} w={50} />
</Stack>
<Skeleton circle height={20} />
</Group>
</ComponentGlobal_CardStyles> </ComponentGlobal_CardStyles>
))} ))}
</> </>
); );
} }
function Collaboration_SkeletonDetail() {
return (
<>
<ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack spacing={"xl"}>
<Grid align="center" gutter={"md"}>
<Grid.Col span={"content"}>
<Skeleton circle height={40} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={150} />
</Grid.Col>
</Grid>
<Center>
<Skeleton height={20} w={200} />
</Center>
<Grid align="center" gutter={"md"}>
<Grid.Col span={"content"}>
<Skeleton h={20} w={70} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={200} />
</Grid.Col>
</Grid>
<Grid align="center" gutter={"md"}>
<Grid.Col span={"content"}>
<Skeleton h={20} w={70} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={200} />
</Grid.Col>
</Grid>
<Skeleton height={20} w={100} />
<Skeleton height={20} w={"100%"} />
<Skeleton height={20} w={100} />
<Skeleton height={20} w={"100%"} />
</Stack>
</ComponentGlobal_CardStyles>
</>
);
}
function Collaboration_SkeletonListPrtisipanIsUser() {
return (
<>
<Stack>
<ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack>
<Center>
<Skeleton h={20} w={100} />
</Center>
{Array.from(new Array(2)).map((e, i) => (
<Grid align="center" gutter={"md"} key={i}>
<Grid.Col span={"content"}>
<Skeleton circle height={40} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={150} />
</Grid.Col>
</Grid>
))}
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</>
);
}
function Collaboration_SkeletonListPartisipan() {
return (
<>
<Stack>
<Center>
<Skeleton h={40} w={150} radius={"xl"} />
</Center>
<ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack>
<Center>
<Skeleton h={20} w={100} />
</Center>
{Array.from(new Array(2)).map((e, i) => (
<Grid align="center" gutter={"md"} key={i}>
<Grid.Col span={"content"}>
<Skeleton circle height={40} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={150} />
</Grid.Col>
</Grid>
))}
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</>
);
}
function Collaboration_SkeletonDetailInfoGroup() {
return (
<>
<Stack>
<ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack spacing={"xl"}>
<Center>
<Skeleton height={20} w={200} />
</Center>
<Grid align="center" gutter={"md"}>
<Grid.Col span={"content"}>
<Skeleton h={20} w={70} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={200} />
</Grid.Col>
</Grid>
<Grid align="center" gutter={"md"}>
<Grid.Col span={"content"}>
<Skeleton h={20} w={70} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={200} />
</Grid.Col>
</Grid>
<Skeleton height={20} w={100} />
<Skeleton height={20} w={"100%"} />
<Skeleton height={20} w={"100%"} />
<Skeleton height={20} w={100} />
<Skeleton height={20} w={"100%"} />
<Skeleton height={20} w={"100%"} />
</Stack>
</ComponentGlobal_CardStyles>
<ComponentGlobal_CardStyles marginBottom={"0"}>
<Stack>
<Skeleton h={20} w={100} />
{Array.from(new Array(2)).map((e, i) => (
<Grid align="center" gutter={"md"} key={i}>
<Grid.Col span={"content"}>
<Skeleton circle height={40} />
</Grid.Col>
<Grid.Col span={3}>
<Skeleton height={20} w={150} />
</Grid.Col>
</Grid>
))}
</Stack>
</ComponentGlobal_CardStyles>
</Stack>
</>
);
}

View File

@@ -5,26 +5,22 @@ import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/inpu
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil"; import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal"; import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan"; import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
import { clientLogger } from "@/util/clientLogger";
import mqtt_client from "@/util/mqtt_client";
import { import {
Button, Button,
Center,
Select, Select,
Stack, Stack,
TextInput, TextInput,
Textarea, Textarea
Loader,
} from "@mantine/core"; } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Collaboration_SkeletonCreate } from "../component";
import { apiGetMasterCollaboration } from "../component/lib/api_collaboration";
import colab_funCreateProyek from "../fun/create/fun_create_proyek"; import colab_funCreateProyek from "../fun/create/fun_create_proyek";
import { MODEL_COLLABORATION_MASTER } from "../model/interface"; import { MODEL_COLLABORATION_MASTER } from "../model/interface";
import mqtt_client from "@/util/mqtt_client";
import { useHookstate } from "@hookstate/core";
import { useGsCollabCreate } from "../global_state/state";
import { useShallowEffect } from "@mantine/hooks";
import { apiGetMasterCollaboration } from "../component/lib/api_collaboration";
import { clientLogger } from "@/util/clientLogger";
import { Collaboration_SkeletonCreate } from "../component";
export default function Colab_Create() { export default function Colab_Create() {
const [value, setValue] = useState({ const [value, setValue] = useState({
@@ -103,7 +99,7 @@ export default function Colab_Create() {
}} }}
/> />
{/* <Select <Select
styles={{ styles={{
label: { label: {
color: "white", color: "white",
@@ -122,25 +118,7 @@ export default function Colab_Create() {
projectCollaborationMaster_IndustriId: val as any, projectCollaborationMaster_IndustriId: val as any,
}); });
}} }}
/> */} />
{/* <TextInput
description={
<Text fz={10}>
minimal partisipan yang akan di pilih untuk mendiskusikan proyek
</Text>
}
type="number"
withAsterisk
label="Jumlah Partisipan"
placeholder={"2"}
onChange={(val) => {
setValue({
...value,
jumlah_partisipan: val.currentTarget.value as any,
});
}}
/> */}
<Stack spacing={5}> <Stack spacing={5}>
<Textarea <Textarea
@@ -207,7 +185,6 @@ function ButtonAction({ value }: { value: any }) {
JSON.stringify({ isNewPost: true, count: 1 }) JSON.stringify({ isNewPost: true, count: 1 })
); );
console.log(value.jumlah_partisipan);
if (value.title === "") if (value.title === "")
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data"); return ComponentGlobal_NotifikasiPeringatan("Lengkapi Data");
if (value.lokasi === "") if (value.lokasi === "")
@@ -227,7 +204,6 @@ function ButtonAction({ value }: { value: any }) {
} }
} }
// console.log(value);
return ( return (
<> <>

View File

@@ -26,7 +26,7 @@ import {
IconSend, IconSend,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import _ from "lodash"; import _ from "lodash";
import { useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import useInfiniteScroll, { import useInfiniteScroll, {
ScrollDirection, ScrollDirection,
@@ -43,6 +43,8 @@ import {
MainColor, MainColor,
} from "@/app_modules/_global/color/color_pallet"; } from "@/app_modules/_global/color/color_pallet";
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader"; import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import { apiGetDataGroupById } from "../../_lib/api_collaboration";
import { clientLogger } from "@/util/clientLogger";
export default function Colab_GroupChatView({ export default function Colab_GroupChatView({
userLoginId, userLoginId,
@@ -55,6 +57,7 @@ export default function Colab_GroupChatView({
selectRoom: MODEL_COLLABORATION_ROOM_CHAT; selectRoom: MODEL_COLLABORATION_ROOM_CHAT;
dataUserLogin: MODEL_USER; dataUserLogin: MODEL_USER;
}) { }) {
const params = useParams<{ id: string }>();
const router = useRouter(); const router = useRouter();
const [loadingBack, setLoadingBack] = useState(false); const [loadingBack, setLoadingBack] = useState(false);
const [loadingInfo, setLoadingInfo] = useState(false); const [loadingInfo, setLoadingInfo] = useState(false);
@@ -66,6 +69,30 @@ export default function Colab_GroupChatView({
const [isGet, setIsGet] = useState(true); const [isGet, setIsGet] = useState(true);
const [newMessageId, setIdMessage] = useState(""); const [newMessageId, setIdMessage] = useState("");
// NEW
const [dataGroup, setDataGroup] =
useState<MODEL_COLLABORATION_ROOM_CHAT | null>(null);
useShallowEffect(() => {
onLoadDataGroup();
}, []);
async function onLoadDataGroup() {
try {
const respone = await apiGetDataGroupById({
id: params.id,
kategori: "detail",
});
if (respone) {
setDataGroup(respone.data);
}
} catch (error) {
clientLogger.error("Error get data group", error);
}
}
const next = async (direction: ScrollDirection) => { const next = async (direction: ScrollDirection) => {
try { try {
setIsLoading(true); setIsLoading(true);
@@ -220,7 +247,9 @@ export default function Colab_GroupChatView({
radius={"xl"} radius={"xl"}
onClick={() => { onClick={() => {
setLoadingInfo(true); setLoadingInfo(true);
router.push(RouterColab.info_grup + selectRoom.id, {scroll: false}); router.push(RouterColab.info_grup + selectRoom.id, {
scroll: false,
});
}} }}
> >
{loadingInfo ? ( {loadingInfo ? (

View File

@@ -1,56 +1,90 @@
"use client"; "use client";
import { AccentColor } from "@/app_modules/_global/color/color_pallet"; import {
import { ComponentGlobal_AvatarAndUsername, ComponentGlobal_CardStyles } from "@/app_modules/_global/component"; ComponentGlobal_AvatarAndUsername,
ComponentGlobal_CardStyles,
} from "@/app_modules/_global/component";
import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_tamplate"; import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_tamplate";
import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate"; import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate";
import { Box, Paper, Stack, Title } from "@mantine/core"; import { clientLogger } from "@/util/clientLogger";
import { Box, Stack, Title } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useParams } from "next/navigation";
import { useState } from "react";
import {
apiGetDataGroupById
} from "../../_lib/api_collaboration";
import ComponentColab_DetailData from "../../component/detail/detail_data"; import ComponentColab_DetailData from "../../component/detail/detail_data";
import { MODEL_COLLABORATION_ROOM_CHAT } from "../../model/interface"; import {
Collaboration_SkeletonDetailInfoGroup
} from "../../component/skeleton_view";
import {
MODEL_COLLABORATION_ROOM_CHAT
} from "../../model/interface";
export default function Colab_DetailInfoGrup({ export default function Colab_DetailInfoGrup() {
dataRoom,
}: {
dataRoom: MODEL_COLLABORATION_ROOM_CHAT;
}) {
return ( return (
<> <>
<UIGlobal_LayoutTamplate <UIGlobal_LayoutTamplate
header={<UIGlobal_LayoutHeaderTamplate title="Info Grup" />} header={<UIGlobal_LayoutHeaderTamplate title="Info Grup" />}
> >
<InfoGroup dataRoom={dataRoom} /> <InfoGroup />
</UIGlobal_LayoutTamplate> </UIGlobal_LayoutTamplate>
</> </>
); );
} }
function InfoGroup({ dataRoom }: { dataRoom: MODEL_COLLABORATION_ROOM_CHAT }) { function InfoGroup() {
const params = useParams<{ id: string }>();
const [data, setData] = useState<MODEL_COLLABORATION_ROOM_CHAT | null>(null);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetDataGroupById({
id: params.id,
kategori: "info_group",
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get data info group", error);
}
}
if (_.isNull(data)) {
return (
<>
<Collaboration_SkeletonDetailInfoGroup />
</>
);
}
return ( return (
<> <>
<ComponentGlobal_CardStyles> <Stack>
<Stack> <ComponentGlobal_CardStyles marginBottom={"0px"}>
<ComponentColab_DetailData data={dataRoom.ProjectCollaboration} /> <ComponentColab_DetailData data={data?.ProjectCollaboration} />
<Paper </ComponentGlobal_CardStyles>
style={{ <ComponentGlobal_CardStyles>
border: `2px solid ${AccentColor.softblue}`, <Stack>
backgroundColor: AccentColor.blue, <Title order={6}>Anggota Grup</Title>
color: "white", {data?.ProjectCollaboration_AnggotaRoomChat.map((e, i) => (
borderRadius: "10px", <Box mb={"sm"} key={i}>
padding: "15px", <ComponentGlobal_AvatarAndUsername
}} profile={e.User.Profile as any}
> />
<Stack> </Box>
<Title order={6}>Anggota Grup</Title> ))}
{dataRoom.ProjectCollaboration_AnggotaRoomChat.map((e, i) => ( </Stack>
<Box key={i}> </ComponentGlobal_CardStyles>
</Stack>
<ComponentGlobal_AvatarAndUsername profile={e.User.Profile as any}/>
</Box>
))}
</Stack>
</Paper>
</Stack>
</ComponentGlobal_CardStyles>
</> </>
); );
} }

View File

@@ -1,38 +1,26 @@
"use client"; "use client";
import { AccentColor } from "@/app_modules/_global/color/color_pallet"; import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { Center, Stack, Loader } from "@mantine/core"; import { clientLogger } from "@/util/clientLogger";
import { Stack } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useParams } from "next/navigation";
import { useState } from "react";
import { apiGetOneCollaborationById } from "../../_lib/api_collaboration";
import ComponentColab_DetailData from "../../component/detail/detail_data"; import ComponentColab_DetailData from "../../component/detail/detail_data";
import ComponentColab_DetailListPartisipasiUser from "../../component/detail/list_partisipasi_user"; import ComponentColab_DetailListPartisipasiUser from "../../component/detail/list_partisipasi_user";
import ComponentColab_AuthorNameOnHeader from "../../component/header_author_name"; import ComponentColab_AuthorNameOnHeader from "../../component/header_author_name";
import { Collaboration_SkeletonDetail } from "../../component/skeleton_view";
import { MODEL_COLLABORATION } from "../../model/interface"; import { MODEL_COLLABORATION } from "../../model/interface";
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { clientLogger } from "@/util/clientLogger";
import { useShallowEffect } from "@mantine/hooks";
import { useState } from "react";
import {
apiGetAllCollaboration,
apiGetOneCollaborationById,
} from "../../_lib/api_collaboration";
import { useParams } from "next/navigation";
import _ from "lodash";
export default function Colab_MainDetail({ export default function Colab_MainDetail({
dataColab,
userLoginId, userLoginId,
listPartisipan,
cekPartisipan,
}: { }: {
dataColab?: MODEL_COLLABORATION;
userLoginId?: string; userLoginId?: string;
listPartisipan?: any[];
cekPartisipan: boolean;
}) { }) {
const params = useParams<{ id: string }>(); const params = useParams<{ id: string }>();
const [data, setData] = useState<MODEL_COLLABORATION | null>(null); const [data, setData] = useState<MODEL_COLLABORATION | null>(null);
const [activePage, setActivePage] = useState(1);
const [isNewPost, setIsNewPost] = useState(false);
useShallowEffect(() => { useShallowEffect(() => {
onLoadData(); onLoadData();
@@ -42,6 +30,7 @@ export default function Colab_MainDetail({
try { try {
const respone = await apiGetOneCollaborationById({ const respone = await apiGetOneCollaborationById({
id: params.id, id: params.id,
kategori: "detail",
}); });
if (respone) { if (respone) {
@@ -52,38 +41,27 @@ export default function Colab_MainDetail({
} }
} }
if (_.isNull(data)) {
return (
<>
<Center>
<Loader />
</Center>
</>
);
}
return ( return (
<> <>
<Stack> <Stack>
<ComponentGlobal_CardStyles> {_.isNull(data) ? (
<Stack> <Collaboration_SkeletonDetail />
<ComponentColab_AuthorNameOnHeader ) : (
tglPublish={new Date()} <ComponentGlobal_CardStyles>
profile={data?.Author?.Profile as any} <Stack>
/> <ComponentColab_AuthorNameOnHeader
<ComponentColab_DetailData data={data as any} /> tglPublish={data.createdAt}
</Stack> profile={data?.Author?.Profile as any}
</ComponentGlobal_CardStyles> />
<ComponentColab_DetailData data={data as any} />
</Stack>
</ComponentGlobal_CardStyles>
)}
<ComponentColab_DetailListPartisipasiUser <ComponentColab_DetailListPartisipasiUser
listPartisipan={listPartisipan} userLoginId={userLoginId}
userLoginId={userLoginId} authorId={data?.Author.id}
authorId={data?.Author.id} />
colabId={data?.id}
cekPartisipan={cekPartisipan}
/>
{/* <ComponentGlobal_CardStyles>
</ComponentGlobal_CardStyles> */}
</Stack> </Stack>
</> </>
); );

View File

@@ -1,36 +1,60 @@
"use client"; "use client";
import { AccentColor } from "@/app_modules/_global/color/color_pallet";
import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component"; import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { apiGetOneCollaborationById } from "@/app_modules/colab/_lib/api_collaboration";
import ComponentColab_DetailData from "@/app_modules/colab/component/detail/detail_data"; import ComponentColab_DetailData from "@/app_modules/colab/component/detail/detail_data";
import ComponentColab_DetailListPartisipasiUser from "@/app_modules/colab/component/detail/list_partisipasi_user"; import ComponentColab_DetailListPartisipasiUser from "@/app_modules/colab/component/detail/list_partisipasi_user";
import ComponentColab_AuthorNameOnHeader from "@/app_modules/colab/component/header_author_name"; import ComponentColab_AuthorNameOnHeader from "@/app_modules/colab/component/header_author_name";
import { import { Collaboration_SkeletonDetail } from "@/app_modules/colab/component/skeleton_view";
MODEL_COLLABORATION, import { MODEL_COLLABORATION } from "@/app_modules/colab/model/interface";
MODEL_COLLABORATION_PARTISIPASI, import { clientLogger } from "@/util/clientLogger";
} from "@/app_modules/colab/model/interface"; import { Stack } from "@mantine/core";
import { Stack, Text } from "@mantine/core"; import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash";
import { useParams } from "next/navigation";
import { useState } from "react";
export default function Colab_DetailPartisipasiProyek() {
const params = useParams<{ id: string }>();
const [data, setData] = useState<MODEL_COLLABORATION | null>(null);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetOneCollaborationById({
id: params.id,
kategori: "detail",
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get all collaboration", error);
}
}
export default function Colab_DetailPartisipasiProyek({
dataColab,
listPartisipan,
}: {
dataColab: MODEL_COLLABORATION;
listPartisipan: MODEL_COLLABORATION_PARTISIPASI[];
}) {
return ( return (
<> <>
<ComponentGlobal_CardStyles> {_.isNull(data) ? (
<Collaboration_SkeletonDetail />
) : (
<Stack> <Stack>
<ComponentColab_AuthorNameOnHeader <ComponentGlobal_CardStyles>
profile={dataColab.Author.Profile} <Stack>
/> <ComponentColab_AuthorNameOnHeader
<ComponentColab_DetailData data={dataColab} /> profile={data.Author.Profile}
<ComponentColab_DetailListPartisipasiUser />
listPartisipan={listPartisipan} <ComponentColab_DetailData data={data} />
/> </Stack>
</ComponentGlobal_CardStyles>
<ComponentColab_DetailListPartisipasiUser />
</Stack> </Stack>
</ComponentGlobal_CardStyles> )}
</> </>
); );
} }

View File

@@ -9,83 +9,120 @@ import { ComponentGlobal_CardStyles } from "@/app_modules/_global/component";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil"; import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal"; import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan"; import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
import { apiGetOneCollaborationById } from "@/app_modules/colab/_lib/api_collaboration";
import ComponentColab_DetailData from "@/app_modules/colab/component/detail/detail_data"; import ComponentColab_DetailData from "@/app_modules/colab/component/detail/detail_data";
import ComponentColab_AuthorNameOnListPartisipan from "@/app_modules/colab/component/detail/header_author_list_partisipan"; import ComponentColab_AuthorNameOnListPartisipan from "@/app_modules/colab/component/detail/header_author_list_partisipan";
import ComponentColab_IsEmptyData from "@/app_modules/colab/component/is_empty_data"; import ComponentColab_IsEmptyData from "@/app_modules/colab/component/is_empty_data";
import {
Collaboration_SkeletonDetail,
Collaboration_SkeletonListPrtisipanIsUser,
} from "@/app_modules/colab/component/skeleton_view";
import colab_funCreateRoomChat from "@/app_modules/colab/fun/create/fun_create_room_chat"; import colab_funCreateRoomChat from "@/app_modules/colab/fun/create/fun_create_room_chat";
import { gs_colab_hot_menu } from "@/app_modules/colab/global_state"; import { gs_colab_hot_menu } from "@/app_modules/colab/global_state";
import { import {
MODEL_COLLABORATION, MODEL_COLLABORATION,
MODEL_COLLABORATION_PARTISIPASI, MODEL_COLLABORATION_PARTISIPASI,
} from "@/app_modules/colab/model/interface"; } from "@/app_modules/colab/model/interface";
import mqtt_client from "@/util/mqtt_client"; import { clientLogger } from "@/util/clientLogger";
import { import {
ActionIcon, ActionIcon,
Box,
Button, Button,
Center,
Checkbox, Checkbox,
Drawer, Drawer,
Grid, Grid,
Group, Group,
Paper, Loader,
ScrollArea,
Stack, Stack,
Text, Text,
TextInput, TextInput,
Title, Title,
} from "@mantine/core"; } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks"; import { useDisclosure, useShallowEffect } from "@mantine/hooks";
import { IconX } from "@tabler/icons-react"; import { IconX } from "@tabler/icons-react";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import _ from "lodash"; import _ from "lodash";
import { useRouter } from "next/navigation"; import { ScrollOnly } from "next-scroll-loader";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
export default function Colab_DetailProyekSaya({ export default function Colab_DetailProyekSaya() {
dataColab, const params = useParams<{ id: string }>();
listPartisipan, const [data, setData] = useState<MODEL_COLLABORATION | null>(null);
}: {
dataColab: MODEL_COLLABORATION;
listPartisipan: MODEL_COLLABORATION_PARTISIPASI[];
}) {
return (
<>
<ComponentGlobal_CardStyles marginBottom={"15px"}>
<Stack>
<ComponentColab_DetailData data={dataColab} />
<CheckBoxPartisipan
listPartisipan={listPartisipan}
colabId={dataColab.id}
/>
</Stack>
</ComponentGlobal_CardStyles>
</>
);
}
function CheckBoxPartisipan({ useShallowEffect(() => {
listPartisipan, onLoadData();
colabId, }, []);
}: {
listPartisipan: MODEL_COLLABORATION_PARTISIPASI[]; async function onLoadData() {
colabId: string; try {
}) { const respone = await apiGetOneCollaborationById({
const [value, setValue] = useState<string[]>([]); id: params.id,
kategori: "detail",
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get all collaboration", error);
}
}
return ( return (
<> <>
<Stack> <Stack>
{/* <pre>{JSON.stringify(listPartisipan,null,2)}</pre> */} {_.isNull(data) ? (
<Paper <Collaboration_SkeletonDetail />
style={{ ) : (
border: `2px solid ${AccentColor.softblue}`, <ComponentGlobal_CardStyles marginBottom={"15px"}>
backgroundColor: AccentColor.blue, <ComponentColab_DetailData data={data} />
color: "white", </ComponentGlobal_CardStyles>
borderRadius: "10px", )}
marginBottom: "20px",
padding: "15px", <CheckBoxPartisipan />
}} </Stack>
> </>
{/* {JSON.stringify(value, null, 2)} */} );
}
function CheckBoxPartisipan() {
const params = useParams<{ id: string }>();
const [value, setValue] = useState<string[]>([]);
const [data, setData] = useState<MODEL_COLLABORATION_PARTISIPASI[] | null>(
null
);
const [activePage, setActivePage] = useState(1);
useShallowEffect(() => {
onLoadDataPartisipan();
}, []);
async function onLoadDataPartisipan() {
try {
const respone = await apiGetOneCollaborationById({
id: params.id,
kategori: "list_partisipan",
page: `${activePage}`,
});
if (respone) {
setData(respone.data);
}
} catch (error) {
clientLogger.error("Error get list partisipan", error);
}
}
if (_.isNull(data)) {
return <Collaboration_SkeletonListPrtisipanIsUser />;
}
return (
<>
<Stack mb={"lg"}>
<ComponentGlobal_CardStyles>
<Stack> <Stack>
<Stack spacing={5}> <Stack spacing={5}>
<Text c={"red"} fz={10}> <Text c={"red"} fz={10}>
@@ -94,52 +131,63 @@ function CheckBoxPartisipan({
Pilih user yang akan menjadi tim proyek anda Pilih user yang akan menjadi tim proyek anda
</Text> </Text>
</Text> </Text>
{/* <Text c={"red"} fz={10}>
*
<Text px={"xs"} span inherit c={"white"}>
Room chat dapat dibentuk jika ada 2 user yang dipilih
</Text>
</Text> */}
</Stack> </Stack>
<ScrollArea h={400} offsetScrollbars>
<Checkbox.Group value={value} onChange={setValue}> {_.isEmpty(data) ? (
<Stack mt="xs"> <ComponentColab_IsEmptyData text="Tidak Ada Pertisipan" />
{_.isEmpty(listPartisipan) ? ( ) : (
<ComponentColab_IsEmptyData text="Tidak Ada Pertisipan" /> <Box>
) : ( <ScrollOnly
listPartisipan.map((e, i) => ( height="50vh"
<Grid key={i} align="center"> renderLoading={() => (
<Center mt={"lg"}>
<Loader color={"yellow"} />
</Center>
)}
data={data}
setData={setData as any}
moreData={async () => {
const respone = await apiGetOneCollaborationById({
id: params.id,
kategori: "list_partisipan",
page: `${activePage + 1}`,
});
setActivePage((val) => val + 1);
return respone.data;
}}
>
{(item) => (
<Checkbox.Group value={value} onChange={setValue}>
<Grid key={item} align="center">
<Grid.Col span={2}> <Grid.Col span={2}>
<Checkbox color={"yellow"} value={e?.User?.id} /> <Checkbox color={"yellow"} value={item.User?.id} />
</Grid.Col> </Grid.Col>
<Grid.Col span={"auto"}> <Grid.Col span={"auto"}>
<ComponentColab_AuthorNameOnListPartisipan <ComponentColab_AuthorNameOnListPartisipan
isPembatas={true} isPembatas={true}
author={e?.User} author={item.User}
deskripsi={e?.deskripsi_diri} deskripsi={item.deskripsi_diri}
/> />
</Grid.Col> </Grid.Col>
</Grid> </Grid>
)) </Checkbox.Group>
)} )}
</Stack> </ScrollOnly>
</Checkbox.Group> </Box>
</ScrollArea> )}
</Stack> </Stack>
</Paper> </ComponentGlobal_CardStyles>
<ButtonAction value={value} colabId={colabId} />
<ButtonAction value={value} />
</Stack> </Stack>
</> </>
); );
} }
function ButtonAction({ function ButtonAction({ value }: { value: string[] }) {
value, const params = useParams<{ id: string }>();
colabId,
}: {
value: string[];
colabId: string;
}) {
const router = useRouter(); const router = useRouter();
const [opened, { open, close }] = useDisclosure(false); const [opened, { open, close }] = useDisclosure(false);
const [hotMenu, setHotMenu] = useAtom(gs_colab_hot_menu); const [hotMenu, setHotMenu] = useAtom(gs_colab_hot_menu);
@@ -147,29 +195,35 @@ function ButtonAction({
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
async function onSave() { async function onSave() {
if (nameRoom === "") try {
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Nama Grup"); setLoading(true);
if (nameRoom === "")
return ComponentGlobal_NotifikasiPeringatan("Lengkapi Nama Grup");
// await notifikasiToUser_CreateGroupCollaboration({ colabId: colabId }); // await notifikasiToUser_CreateGroupCollaboration({ colabId: colabId });
const res = await colab_funCreateRoomChat(nameRoom, value, colabId); const res = await colab_funCreateRoomChat(nameRoom, value, params.id);
if (res.status === 201) { if (res.status === 201) {
for (let a of value) { // for (let a of value) {
mqtt_client.publish( // mqtt_client.publish(
"USER", // "USER",
JSON.stringify({ // JSON.stringify({
userId: a, // userId: a,
count: 1, // count: 1,
}) // })
); // );
// }
ComponentGlobal_NotifikasiBerhasil("Berhasil Membuat Grup");
setHotMenu(4);
router.replace(RouterColab.grup_diskusi);
} else {
ComponentGlobal_NotifikasiGagal("Gagal Membuat Grup");
} }
} catch (error) {
setLoading(true); clientLogger.error("Error create room chat", error);
ComponentGlobal_NotifikasiBerhasil("Berhasil Membuat Grup"); } finally {
setHotMenu(4); setLoading(false);
router.push(RouterColab.grup_diskusi);
} else {
ComponentGlobal_NotifikasiGagal("Gagal Membuat Grup");
} }
} }
@@ -188,7 +242,7 @@ function ButtonAction({
transition: "0.5s", transition: "0.5s",
}} }}
> >
Buat Ruang Diskusi{" "} Buat Ruang Diskusi
</Button> </Button>
<Drawer <Drawer

View File

@@ -6,22 +6,22 @@ import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_ta
import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate"; import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate";
import { ActionIcon } from "@mantine/core"; import { ActionIcon } from "@mantine/core";
import { IconDotsVertical, IconEdit } from "@tabler/icons-react"; import { IconDotsVertical, IconEdit } from "@tabler/icons-react";
import { useParams } from "next/navigation";
import React, { useState } from "react"; import React, { useState } from "react";
export default function LayoutColab_DetailProyekSaya({ export default function LayoutColab_DetailProyekSaya({
children, children,
colabId,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
colabId: string;
}) { }) {
const params = useParams<{id: string}>()
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const listPage = [ const listPage = [
{ {
id: "1", id: "1",
name: "Edit Proyek", name: "Edit Proyek",
icon: <IconEdit />, icon: <IconEdit />,
path: RouterColab.edit + colabId, path: RouterColab.edit + params.id,
}, },
]; ];

View File

@@ -2,17 +2,29 @@
import prisma from "@/app/lib/prisma"; import prisma from "@/app/lib/prisma";
import { RouterColab } from "@/app/lib/router_hipmi/router_colab"; import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { revalidatePath } from "next/cache"; import { revalidatePath } from "next/cache";
export default async function colab_funCreatePartisipan( export default async function colab_funCreatePartisipan({
colabId: string, id,
userId: string, deskripsi,
deskripsi: string }: {
) { id: string;
deskripsi: string;
}) {
const userLoginId = await funGetUserIdByToken();
if (userLoginId == null) {
return {
status: 500,
message: "Gagal mendapatkan data, user id tidak ada",
};
}
const create = await prisma.projectCollaboration_Partisipasi.create({ const create = await prisma.projectCollaboration_Partisipasi.create({
data: { data: {
projectCollaborationId: colabId, projectCollaborationId: id,
userId: userId, userId: userLoginId,
deskripsi_diri: deskripsi, deskripsi_diri: deskripsi,
}, },
select: { select: {
@@ -27,7 +39,7 @@ export default async function colab_funCreatePartisipan(
}); });
if (!create) return { status: 400, message: "Gagal menambahkan partisipan" }; if (!create) return { status: 400, message: "Gagal menambahkan partisipan" };
revalidatePath(RouterColab.main_detail + colabId); revalidatePath(RouterColab.main_detail + id);
return { return {
data: create, data: create,
status: 201, status: 201,

View File

@@ -2,17 +2,16 @@
import { RouterColab } from "@/app/lib/router_hipmi/router_colab"; import { RouterColab } from "@/app/lib/router_hipmi/router_colab";
import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data"; import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import { clientLogger } from "@/util/clientLogger";
import { Box, Center, Loader } from "@mantine/core"; import { Box, Center, Loader } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import _ from "lodash"; import _ from "lodash";
import { ScrollOnly } from "next-scroll-loader"; import { ScrollOnly } from "next-scroll-loader";
import { useState } from "react"; import { useState } from "react";
import { ComponentColab_CardSemuaPartisipan } from "../../component/card_view/card_semua_partisipan";
import colab_getListPartisipasiProyekByAuthorId from "../../fun/get/pasrtisipan/get_list_partisipasi_proyek_by_author_id";
import { MODEL_COLLABORATION_PARTISIPASI } from "../../model/interface";
import { useShallowEffect } from "@mantine/hooks";
import { apiGetAllCollaboration } from "../../_lib/api_collaboration"; import { apiGetAllCollaboration } from "../../_lib/api_collaboration";
import { clientLogger } from "@/util/clientLogger"; import { ComponentColab_CardSemuaPartisipan } from "../../component/card_view/card_semua_partisipan";
import { Collaboration_SkeletonBeranda } from "../../component/skeleton_view"; import { Collaboration_SkeletonBeranda } from "../../component/skeleton_view";
import { MODEL_COLLABORATION_PARTISIPASI } from "../../model/interface";
export default function Colab_PartisipasiProyek() { export default function Colab_PartisipasiProyek() {
const [data, setData] = useState<MODEL_COLLABORATION_PARTISIPASI[] | null>( const [data, setData] = useState<MODEL_COLLABORATION_PARTISIPASI[] | null>(