Compare commits
111 Commits
amalia/30-
...
amalia/02-
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fd9395fc1 | |||
| 1f259a409b | |||
| 55c932ab89 | |||
| b4ee1bc996 | |||
| 9a6a4d66df | |||
| 6910f8fdff | |||
| e20f5c11e4 | |||
| 8e18ad0e77 | |||
| 6e30190161 | |||
| 67d338ac84 | |||
| f7e84314fb | |||
| 5fc34eb49b | |||
| bbd610910d | |||
| 7f8214172c | |||
| 7af2f8044e | |||
| 0eba2209d1 | |||
| c3ce77b0dc | |||
| 4acd7f901a | |||
| 4064497794 | |||
| ae3131ecf8 | |||
| 9c07375015 | |||
| 4b1d2e28dc | |||
| fdfa526d8c | |||
| 862ee0001f | |||
| 09d1088fac | |||
| bbe016c03d | |||
| c51692079e | |||
| fbfdc21b9d | |||
| 51b39396ec | |||
| 18589b7de7 | |||
| e49fb11c94 | |||
| d3f4478bb1 | |||
| 006754a337 | |||
| 54d708d109 | |||
| 6ed16d05b9 | |||
| b78013c160 | |||
| bef4dd1969 | |||
| f10b87f0f2 | |||
| 2e4eaaec95 | |||
| f87b99f704 | |||
| 83085418ed | |||
| f8ece570b1 | |||
| 648f23c760 | |||
| 3af2a2ef05 | |||
| cacc8c72b3 | |||
| dfa7b571f1 | |||
| 2e4ab4f861 | |||
| a533f3b085 | |||
| 4810fecb10 | |||
| 3af4d84e55 | |||
| f3fa9eab99 | |||
| 96088dad07 | |||
| 303f646ff1 | |||
| dce9366fab | |||
| e345e97023 | |||
| d114b9b06d | |||
| d7a90db6a7 | |||
| e48ff58c48 | |||
| 4a57ffd69c | |||
| cc72323891 | |||
| ed133a7452 | |||
| 5f81128a97 | |||
| 62684557ba | |||
| 562470bcd3 | |||
| 0987978cb4 | |||
| b5f1c2ebdd | |||
| ca699f1430 | |||
| a402d8ba51 | |||
| a0fbfb39b3 | |||
| 1621e95af2 | |||
| cb50197158 | |||
| 523826c376 | |||
| e5eb2e1cc2 | |||
| 25b37909f5 | |||
| 772439031d | |||
| 3bbfadb45e | |||
| 4ff905eba9 | |||
| bda9b4ba85 | |||
| 215fb59ec7 | |||
| 10e0619789 | |||
| 60c4a11d64 | |||
| 99b64e1a70 | |||
| 90e61422cf | |||
| 20032301e8 | |||
| 19c99534c5 | |||
| 6147223b34 | |||
| d000910b9f | |||
| 499c7441ad | |||
| acfc574616 | |||
| aef1c5ed84 | |||
| 60215f49a5 | |||
| bcbdc4c02b | |||
| 4e64f041e9 | |||
| 3ec93ffe02 | |||
| 2bf919ac09 | |||
| 7be78fad14 | |||
| f3317a7190 | |||
| 1f856ad3ab | |||
| 2c98c2581d | |||
| 9df5a33386 | |||
| b0dca49e04 | |||
| 09772910b7 | |||
| b075dae4b3 | |||
| 9b4dec8a39 | |||
| 494853db06 | |||
| b625328789 | |||
| 3561f80bf6 | |||
| c4d454ea58 | |||
| b4b6076693 | |||
| e766a6059d | |||
| 7086a56e00 |
2573
darmasaba-api-ai.yml
Normal file
2573
darmasaba-api-ai.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -107,13 +107,13 @@ model User {
|
||||
gender String @default("M") //M= Male, F= Female
|
||||
img String?
|
||||
isFirstLogin Boolean @default(true)
|
||||
isWithoutOTP Boolean @default(false)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
Announcement Announcement[]
|
||||
Project Project[]
|
||||
ProjectMember ProjectMember[]
|
||||
ProjectComment ProjectComment[]
|
||||
UserLog UserLog[]
|
||||
Division Division[]
|
||||
DivisionMember DivisionMember[]
|
||||
@@ -184,24 +184,25 @@ model AnnouncementMember {
|
||||
}
|
||||
|
||||
model Project {
|
||||
id String @id @default(cuid())
|
||||
Village Village @relation(fields: [idVillage], references: [id])
|
||||
idVillage String
|
||||
Group Group @relation(fields: [idGroup], references: [id])
|
||||
idGroup String
|
||||
title String
|
||||
status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled
|
||||
desc String? @db.Text
|
||||
reason String? @db.Text
|
||||
isActive Boolean @default(true)
|
||||
User User @relation(fields: [createdBy], references: [id])
|
||||
createdBy String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ProjectMember ProjectMember[]
|
||||
ProjectFile ProjectFile[]
|
||||
ProjectComment ProjectComment[]
|
||||
ProjectTask ProjectTask[]
|
||||
id String @id @default(cuid())
|
||||
Village Village @relation(fields: [idVillage], references: [id])
|
||||
idVillage String
|
||||
Group Group @relation(fields: [idGroup], references: [id])
|
||||
idGroup String
|
||||
title String
|
||||
status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled
|
||||
desc String? @db.Text
|
||||
reason String? @db.Text
|
||||
report String? @db.Text
|
||||
isActive Boolean @default(true)
|
||||
User User @relation(fields: [createdBy], references: [id])
|
||||
createdBy String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ProjectMember ProjectMember[]
|
||||
ProjectFile ProjectFile[]
|
||||
ProjectTask ProjectTask[]
|
||||
ProjectLink ProjectLink[]
|
||||
}
|
||||
|
||||
model ProjectMember {
|
||||
@@ -228,33 +229,44 @@ model ProjectFile {
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model ProjectTask {
|
||||
id String @id @default(cuid())
|
||||
Project Project @relation(fields: [idProject], references: [id])
|
||||
idProject String
|
||||
title String
|
||||
desc String?
|
||||
status Int @default(0) // 0 = todo, 1 = done
|
||||
notifikasi Boolean @default(false)
|
||||
dateStart DateTime @db.Date
|
||||
dateEnd DateTime @db.Date
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model ProjectComment {
|
||||
model ProjectLink {
|
||||
id String @id @default(cuid())
|
||||
Project Project @relation(fields: [idProject], references: [id])
|
||||
idProject String
|
||||
User User @relation(fields: [createdBy], references: [id])
|
||||
createdBy String
|
||||
comment String @db.Text
|
||||
link String @db.Text
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model ProjectTask {
|
||||
id String @id @default(cuid())
|
||||
Project Project @relation(fields: [idProject], references: [id])
|
||||
idProject String
|
||||
title String
|
||||
desc String?
|
||||
status Int @default(0) // 0 = todo, 1 = done
|
||||
notifikasi Boolean @default(false)
|
||||
dateStart DateTime @db.Date
|
||||
dateEnd DateTime @db.Date
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ProjectTaskDetail ProjectTaskDetail[]
|
||||
}
|
||||
|
||||
model ProjectTaskDetail {
|
||||
id String @id @default(cuid())
|
||||
ProjectTask ProjectTask @relation(fields: [idTask], references: [id])
|
||||
idTask String
|
||||
date DateTime @db.Date
|
||||
timeStart DateTime? @db.Time()
|
||||
timeEnd DateTime? @db.Time()
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Division {
|
||||
id String @id @default(cuid())
|
||||
Village Village @relation(fields: [idVillage], references: [id])
|
||||
@@ -280,6 +292,7 @@ model Division {
|
||||
DivisionCalendar DivisionCalendar[]
|
||||
DivisionCalendarReminder DivisionCalendarReminder[]
|
||||
ContainerFileDivision ContainerFileDivision[]
|
||||
DivisionProjectLink DivisionProjectLink[]
|
||||
}
|
||||
|
||||
model DivisionMember {
|
||||
@@ -302,6 +315,7 @@ model DivisionProject {
|
||||
title String
|
||||
desc String? @db.Text
|
||||
reason String? @db.Text
|
||||
report String? @db.Text
|
||||
status Int @default(0) // 0 = pending, 1 = ongoing, 2 = done, 3 = cancelled
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
@@ -309,25 +323,51 @@ model DivisionProject {
|
||||
DivisionProjectTask DivisionProjectTask[]
|
||||
DivisionProjectMember DivisionProjectMember[]
|
||||
DivisionProjectFile DivisionProjectFile[]
|
||||
DivisionProjectLink DivisionProjectLink[]
|
||||
}
|
||||
|
||||
model DivisionProjectTask {
|
||||
model DivisionProjectLink {
|
||||
id String @id @default(cuid())
|
||||
Division Division @relation(fields: [idDivision], references: [id])
|
||||
idDivision String
|
||||
DivisionProject DivisionProject @relation(fields: [idProject], references: [id])
|
||||
idProject String
|
||||
title String
|
||||
desc String? @db.Text
|
||||
status Int @default(0) // 0 = todo, 1 = done
|
||||
notifikasi Boolean @default(false)
|
||||
dateStart DateTime @db.Date
|
||||
dateEnd DateTime @db.Date
|
||||
link String @db.Text
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model DivisionProjectTask {
|
||||
id String @id @default(cuid())
|
||||
Division Division @relation(fields: [idDivision], references: [id])
|
||||
idDivision String
|
||||
DivisionProject DivisionProject @relation(fields: [idProject], references: [id])
|
||||
idProject String
|
||||
title String
|
||||
desc String? @db.Text
|
||||
status Int @default(0) // 0 = todo, 1 = done
|
||||
notifikasi Boolean @default(false)
|
||||
dateStart DateTime @db.Date
|
||||
dateEnd DateTime @db.Date
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
DivisionProjectTaskDetail DivisionProjectTaskDetail[]
|
||||
}
|
||||
|
||||
model DivisionProjectTaskDetail {
|
||||
id String @id @default(cuid())
|
||||
DivisionProjectTask DivisionProjectTask @relation(fields: [idTask], references: [id])
|
||||
idTask String
|
||||
date DateTime @db.Date
|
||||
timeStart DateTime? @db.Time()
|
||||
timeEnd DateTime? @db.Time()
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model DivisionProjectMember {
|
||||
id String @id @default(cuid())
|
||||
Division Division @relation(fields: [idDivision], references: [id])
|
||||
|
||||
253
public/util/privacy-policy.html
Normal file
253
public/util/privacy-policy.html
Normal file
@@ -0,0 +1,253 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Privacy Policy — Bali Interaktif Perkasa</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--fg: #111111;
|
||||
--muted: #555555;
|
||||
--accent: #0a7cff;
|
||||
--card: #f7f7f8;
|
||||
--border: #e5e7eb;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
|
||||
color: var(--fg);
|
||||
background: var(--bg);
|
||||
line-height: 1.6;
|
||||
}
|
||||
header {
|
||||
padding: 2.5rem 1rem 1rem;
|
||||
background: linear-gradient(180deg, #eef4ff, #fff);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.container {
|
||||
max-width: 840px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem 3rem;
|
||||
}
|
||||
h1 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: clamp(1.6rem, 3vw, 2.2rem);
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.updated {
|
||||
color: var(--muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
nav.toc {
|
||||
background: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 1rem 1.25rem;
|
||||
margin: 1.25rem 0 2rem;
|
||||
}
|
||||
nav.toc h2 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
nav.toc ol {
|
||||
margin: 0.25rem 0 0.5rem 1.25rem;
|
||||
}
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
section { margin: 2rem 0; }
|
||||
h2 {
|
||||
font-size: 1.35rem;
|
||||
margin: 0 0 0.5rem;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
h3 { font-size: 1.05rem; margin: 1rem 0 0.25rem; }
|
||||
.summary {
|
||||
background: #fffef5;
|
||||
border: 1px solid #f1e8c6;
|
||||
border-radius: 12px;
|
||||
padding: 1rem 1.25rem;
|
||||
}
|
||||
ul, ol { padding-left: 1.25rem; }
|
||||
address { font-style: normal; white-space: pre-line; }
|
||||
footer {
|
||||
margin-top: 2.5rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--border);
|
||||
color: var(--muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
code { background: #f1f5f9; padding: 0.1rem 0.3rem; border-radius: 6px; }
|
||||
.lead { font-size: 1.05rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="container">
|
||||
<h1>Privacy Policy</h1>
|
||||
<div class="updated">Last updated September 01, 2025</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<p class="lead">
|
||||
This Privacy Notice for <strong>Bali Interaktif Perkasa</strong> ("we," "us," or "our") describes how and why we might access, collect, store, use, and/or share ("process") your personal information when you use our services ("Services"), including when you:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Download and use our mobile application (<em>Darmasaba mobile</em>), or any other application of ours that links to this Privacy Notice.</li>
|
||||
<li>Use Administration. This mobile application is specifically designed to help village officials manage data and monitor the progress of internal activities. It offers features such as data management by division, general activity monitoring, discussion forums, official announcements, and document folder management.</li>
|
||||
<li>Engage with us in other related ways, including any sales, marketing, or events.</li>
|
||||
</ul>
|
||||
<p>Questions or concerns? Reading this Privacy Notice will help you understand your privacy rights and choices. We are responsible for making decisions about how your personal information is processed. If you do not agree with our policies and practices, please do not use our Services. If you still have any questions or concerns, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
|
||||
<section class="summary">
|
||||
<h2>Summary of Key Points</h2>
|
||||
<p>This summary provides key points from our Privacy Notice, but you can find out more details about any of these topics by using the table of contents below.</p>
|
||||
<ul>
|
||||
<li><strong>What personal information do we process?</strong> We may process personal information depending on how you interact with us and the Services, the choices you make, and the products and features you use.</li>
|
||||
<li><strong>Do we process any sensitive personal information?</strong> We do not process sensitive personal information.</li>
|
||||
<li><strong>Do we collect any information from third parties?</strong> We do not collect any information from third parties.</li>
|
||||
<li><strong>How do we process your information?</strong> To provide, improve, and administer our Services; communicate with you; for security and fraud prevention; and to comply with law. We may also process your information for other purposes with your consent.</li>
|
||||
<li><strong>In what situations and with which parties do we share personal information?</strong> We may share information in specific situations and with specific third parties.</li>
|
||||
<li><strong>How do we keep your information safe?</strong> We have organizational and technical measures to protect your personal information; however, no method is 100% secure.</li>
|
||||
<li><strong>What are your rights?</strong> Depending on your location, you may have certain rights regarding your personal information.</li>
|
||||
<li><strong>How do you exercise your rights?</strong> The easiest way is by emailing <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</li>
|
||||
</ul>
|
||||
<p>Want to learn more about what we do with information we collect? Review the Privacy Notice in full below.</p>
|
||||
</section>
|
||||
|
||||
<nav class="toc" aria-label="Table of contents">
|
||||
<h2>Table of Contents</h2>
|
||||
<ol>
|
||||
<li><a href="#collect">1. WHAT INFORMATION DO WE COLLECT?</a></li>
|
||||
<li><a href="#process">2. HOW DO WE PROCESS YOUR INFORMATION?</a></li>
|
||||
<li><a href="#share">3. WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION?</a></li>
|
||||
<li><a href="#retention">4. HOW LONG DO WE KEEP YOUR INFORMATION?</a></li>
|
||||
<li><a href="#security">5. HOW DO WE KEEP YOUR INFORMATION SAFE?</a></li>
|
||||
<li><a href="#minors">6. DO WE COLLECT INFORMATION FROM MINORS?</a></li>
|
||||
<li><a href="#rights">7. WHAT ARE YOUR PRIVACY RIGHTS?</a></li>
|
||||
<li><a href="#dnt">8. CONTROLS FOR DO-NOT-TRACK FEATURES</a></li>
|
||||
<li><a href="#updates">9. DO WE MAKE UPDATES TO THIS NOTICE?</a></li>
|
||||
<li><a href="#contact">10. HOW CAN YOU CONTACT US ABOUT THIS NOTICE?</a></li>
|
||||
<li><a href="#review">11. HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU?</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<section id="collect">
|
||||
<h2>1. WHAT INFORMATION DO WE COLLECT?</h2>
|
||||
<h3>Personal information you disclose to us</h3>
|
||||
<p><em>In Short:</em> We collect personal information that you provide to us.</p>
|
||||
<p>We collect personal information that you voluntarily provide to us when you express an interest in obtaining information about us or our products and Services, when you participate in activities on the Services, or otherwise when you contact us.</p>
|
||||
<h3>Personal Information Provided by You</h3>
|
||||
<p>The personal information we collect depends on the context of your interactions with us and the Services, the choices you make, and the products and features you use. This may include:</p>
|
||||
<ul>
|
||||
<li>names</li>
|
||||
<li>phone numbers</li>
|
||||
<li>email addresses</li>
|
||||
</ul>
|
||||
<h3>Sensitive Information</h3>
|
||||
<p>We do not process sensitive information.</p>
|
||||
<h3>Application Data</h3>
|
||||
<p>If you use our application(s), we may also collect the following information if you choose to provide us with access or permission:</p>
|
||||
<ul>
|
||||
<li><strong>Mobile Device Access.</strong> We may request access or permission to certain features from your mobile device, including your mobile device's camera, and other features. You may change access or permissions in your device's settings.</li>
|
||||
<li><strong>Push Notifications.</strong> We may request to send you push notifications regarding your account or certain features of the application(s). You may opt out in your device's settings.</li>
|
||||
</ul>
|
||||
<p>This information is primarily needed to maintain the security and operation of our application(s), for troubleshooting, and for internal analytics and reporting purposes.</p>
|
||||
<p>All personal information that you provide to us must be true, complete, and accurate, and you must notify us of any changes to such personal information.</p>
|
||||
</section>
|
||||
|
||||
<section id="process">
|
||||
<h2>2. HOW DO WE PROCESS YOUR INFORMATION?</h2>
|
||||
<p><em>In Short:</em> We process your information to provide, improve, and administer our Services, communicate with you, for security and fraud prevention, and to comply with law. We may also process your information for other purposes with your consent.</p>
|
||||
<p>We process your personal information for a variety of reasons, depending on how you interact with our Services, including:</p>
|
||||
<ul>
|
||||
<li><strong>To deliver and facilitate delivery of services to the user.</strong> We may process your information to provide you with the requested service.</li>
|
||||
<li><strong>To enable user-to-user communications.</strong> We may process your information if you choose to use offerings that allow communication with another user.</li>
|
||||
<li><strong>To evaluate and improve our Services, products, marketing, and your experience.</strong> We may process your information to identify usage trends, determine the effectiveness of our promotional campaigns, and to evaluate and improve our Services, products, marketing, and your experience.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="share">
|
||||
<h2>3. WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION?</h2>
|
||||
<p><em>In Short:</em> We may share information in specific situations described in this section and/or with the following third parties.</p>
|
||||
<p><strong>Vendors, Consultants, and Other Third-Party Service Providers.</strong> We may share your data with third-party vendors, service providers, contractors, or agents ("third parties") who perform services for us or on our behalf and require access to such information to do that work.</p>
|
||||
<p>The third parties we may share personal information with include:</p>
|
||||
<ul>
|
||||
<li><strong>Functionality and Infrastructure Optimization:</strong> Firebase Realtime Database and Cloud Functions for Firebase</li>
|
||||
<li><strong>Functionality & Infrastructure Optimization:</strong> Expo / EAS Services</li>
|
||||
</ul>
|
||||
<p>We may also need to share your personal information in the following situations:</p>
|
||||
<ul>
|
||||
<li><strong>Business Transfers.</strong> We may share or transfer your information in connection with, or during negotiations of, any merger, sale of company assets, financing, or acquisition of all or a portion of our business to another company.</li>
|
||||
<li><strong>Other Users.</strong> When you share personal information (for example, by posting comments or other content to the Services) or interact with public areas of the Services, such information may be viewed by all users and may be publicly available outside the Services in perpetuity. Other users may view descriptions of your activity, communicate with you, and view your profile.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="retention">
|
||||
<h2>4. HOW LONG DO WE KEEP YOUR INFORMATION?</h2>
|
||||
<p><em>In Short:</em> We keep your information for as long as necessary to fulfill the purposes outlined in this Privacy Notice unless otherwise required by law.</p>
|
||||
<p>We will only keep your personal information as long as necessary for the purposes set out in this Privacy Notice, unless a longer retention period is required or permitted by law (such as tax, accounting, or other legal requirements).</p>
|
||||
<p>When we have no ongoing legitimate business need to process your personal information, we will delete or anonymize such information. If deletion is not possible (for example, if your personal information is stored in backup archives), we will securely store your personal information and isolate it from any further processing until deletion is possible.</p>
|
||||
</section>
|
||||
|
||||
<section id="security">
|
||||
<h2>5. HOW DO WE KEEP YOUR INFORMATION SAFE?</h2>
|
||||
<p><em>In Short:</em> We aim to protect your personal information through a system of organizational and technical security measures.</p>
|
||||
<p>We have implemented appropriate and reasonable technical and organizational security measures designed to protect the security of any personal information we process. However, despite our safeguards and efforts to secure your information, no electronic transmission over the Internet or information storage technology can be guaranteed to be 100% secure. Transmission of personal information to and from our Services is at your own risk. You should only access the Services within a secure environment.</p>
|
||||
</section>
|
||||
|
||||
<section id="minors">
|
||||
<h2>6. DO WE COLLECT INFORMATION FROM MINORS?</h2>
|
||||
<p><em>In Short:</em> We do not knowingly collect data from or market to children under 18 years of age.</p>
|
||||
<p>We do not knowingly collect, solicit data from, or market to children under 18 years of age, nor do we knowingly sell such personal information. By using the Services, you represent that you are at least 18 or that you are the parent or guardian of such a minor and consent to such minor dependent’s use of the Services. If we learn that personal information from users less than 18 years of age has been collected, we will deactivate the account and take reasonable measures to promptly delete such data from our records. If you become aware of any data we may have collected from children under age 18, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
</section>
|
||||
|
||||
<section id="rights">
|
||||
<h2>7. WHAT ARE YOUR PRIVACY RIGHTS?</h2>
|
||||
<p><em>In Short:</em> You may review, change, or terminate your account at any time, depending on your country, province, or state of residence.</p>
|
||||
<p><strong>Withdrawing your consent:</strong> If we are relying on your consent to process your personal information (which may be express and/or implied consent depending on the applicable law), you have the right to withdraw your consent at any time. You can do so by contacting us using the details in the section "<a href="#contact">HOW CAN YOU CONTACT US ABOUT THIS NOTICE?</a>" below. This will not affect the lawfulness of the processing before its withdrawal, nor will it affect processing conducted in reliance on lawful processing grounds other than consent where permitted by law.</p>
|
||||
<p>If you have questions or comments about your privacy rights, email us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
</section>
|
||||
|
||||
<section id="dnt">
|
||||
<h2>8. CONTROLS FOR DO-NOT-TRACK FEATURES</h2>
|
||||
<p>Most web browsers and some mobile operating systems and applications include a Do-Not-Track ("DNT") setting you can activate to signal your privacy preference not to have data about your online browsing activities monitored and collected. At this stage, no uniform technology standard for recognizing and implementing DNT signals has been finalized. As such, we do not currently respond to DNT browser signals or any other mechanism that automatically communicates your choice not to be tracked online. If a standard for online tracking is adopted that we must follow in the future, we will inform you about that practice in a revised version of this Privacy Notice.</p>
|
||||
</section>
|
||||
|
||||
<section id="updates">
|
||||
<h2>9. DO WE MAKE UPDATES TO THIS NOTICE?</h2>
|
||||
<p><em>In Short:</em> Yes, we will update this notice as necessary to stay compliant with relevant laws.</p>
|
||||
<p>We may update this Privacy Notice from time to time. The updated version will be indicated by an updated "Revised" date at the top of this Privacy Notice. If we make material changes, we may notify you by prominently posting a notice of such changes or by directly sending you a notification. We encourage you to review this Privacy Notice frequently to stay informed of how we are protecting your information.</p>
|
||||
</section>
|
||||
|
||||
<section id="contact">
|
||||
<h2>10. HOW CAN YOU CONTACT US ABOUT THIS NOTICE?</h2>
|
||||
<address>
|
||||
Bali Interaktif Perkasa
|
||||
Park23 Creative Hub, Bali Interaktif Perkasa - Private Office
|
||||
Jl. Kediri 3rd Floor, Number 01 - 02, Tuban
|
||||
Badung, Bali 80361
|
||||
Indonesia
|
||||
</address>
|
||||
<p>Email: <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a></p>
|
||||
</section>
|
||||
|
||||
<section id="review">
|
||||
<h2>11. HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU?</h2>
|
||||
<p>You have the right to request access to the personal information we collect from you, details about how we have processed it, correct inaccuracies, or delete your personal information. You may also have the right to withdraw your consent to our processing of your personal information. These rights may be limited in some circumstances by applicable law.</p>
|
||||
<p>To make a request, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>© <span id="year"></span> Bali Interaktif Perkasa. All rights reserved.</p>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
document.getElementById('year').textContent = new Date().getFullYear();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NavbarDetailDivisionTask, ProgressDetailTask, ListTugasDetailTask, ListFileDetailTask, ListAnggotaDetailTask } from "@/module/task"
|
||||
import { ListAnggotaDetailTask, ListFileDetailTask, ListLinkDetailTask, ListReportDetailTask, ListTugasDetailTask, NavbarDetailDivisionTask, ProgressDetailTask } from "@/module/task"
|
||||
import { Box } from "@mantine/core"
|
||||
|
||||
function Page() {
|
||||
@@ -7,8 +7,10 @@ function Page() {
|
||||
<NavbarDetailDivisionTask />
|
||||
<Box p={20}>
|
||||
<ProgressDetailTask />
|
||||
<ListReportDetailTask />
|
||||
<ListTugasDetailTask />
|
||||
<ListFileDetailTask />
|
||||
<ListLinkDetailTask />
|
||||
<ListAnggotaDetailTask />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { AddReportTask } from "@/module/task"
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<AddReportTask />
|
||||
)
|
||||
}
|
||||
export default Page
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ListAnggotaDetailProject, ListFileDetailProject, ListTugasDetailProject, NavbarDetailProject, ProgressDetailProject } from '@/module/project';
|
||||
import { ListAnggotaDetailProject, ListFileDetailProject, ListLinkDetailProject, ListReportDetailProject, ListTugasDetailProject, NavbarDetailProject, ProgressDetailProject } from '@/module/project';
|
||||
import { Box } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
@@ -8,8 +7,10 @@ function Page() {
|
||||
<NavbarDetailProject />
|
||||
<Box p={20}>
|
||||
<ProgressDetailProject />
|
||||
<ListReportDetailProject />
|
||||
<ListTugasDetailProject />
|
||||
<ListFileDetailProject />
|
||||
<ListLinkDetailProject />
|
||||
<ListAnggotaDetailProject />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
9
src/app/(application)/project/[id]/report/page.tsx
Normal file
9
src/app/(application)/project/[id]/report/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { AddReportProject } from "@/module/project";
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<AddReportProject />
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
95
src/app/api/ai/announcement/[id]/route.ts
Normal file
95
src/app/api/ai/announcement/[id]/route.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ONE PENGUMUMAN, UNTUK TAMPIL DETAIL PENGUMUMAN
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
|
||||
const data = await prisma.announcement.count({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Gagal mendapatkan pengumuman, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const announcement = await prisma.announcement.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!announcement) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Gagal mendapatkan pengumuman, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
let dataFix = { ...announcement, member: {} };
|
||||
|
||||
const announcementMember = await prisma.announcementMember.findMany({
|
||||
where: {
|
||||
idAnnouncement: id,
|
||||
},
|
||||
select: {
|
||||
idGroup: true,
|
||||
idDivision: true,
|
||||
Group: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
Division: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formatMember = announcementMember.map((v: any) => ({
|
||||
..._.omit(v, ["Group", "Division"]),
|
||||
idGroup: v.idGroup,
|
||||
idDivision: v.idDivision,
|
||||
group: v.Group.name,
|
||||
division: v.Division.name
|
||||
}))
|
||||
|
||||
dataFix.member = formatMember
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: true,
|
||||
message: "Berhasil mendapatkan pengumuman",
|
||||
data: dataFix,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan pengumuman, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
52
src/app/api/ai/announcement/route.ts
Normal file
52
src/app/api/ai/announcement/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import "moment/locale/id";
|
||||
import { NextResponse } from "next/server";
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
|
||||
|
||||
// GET ALL PENGUMUMAN
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const judul = searchParams.get('search');
|
||||
const page = searchParams.get('page');
|
||||
const get = searchParams.get('get');
|
||||
const villageId = searchParams.get('desa');
|
||||
const active = searchParams.get('active');
|
||||
|
||||
let getFix = 0;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
|
||||
let kondisi: any = {
|
||||
idVillage: String(villageId),
|
||||
isActive: (active == "false" || active == undefined) ? false : true,
|
||||
title: {
|
||||
contains: (judul == undefined || judul == null) ? "" : judul,
|
||||
mode: "insensitive"
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.announcement.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan pengumuman", data, }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan pengumuman, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
21
src/app/api/ai/banner/[id]/route.ts
Normal file
21
src/app/api/ai/banner/[id]/route.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ONE BANNER
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
|
||||
const data = await prisma.bannerImage.findUnique({
|
||||
where: {
|
||||
id: String(id)
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan banner", data }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan banner, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
48
src/app/api/ai/banner/route.ts
Normal file
48
src/app/api/ai/banner/route.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL BANNER
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const judul = searchParams.get('search');
|
||||
const page = searchParams.get('page');
|
||||
const get = searchParams.get('get');
|
||||
const villageId = searchParams.get('desa');
|
||||
const active = searchParams.get('active');
|
||||
|
||||
let getFix = 0;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
idVillage: String(villageId),
|
||||
isActive: (active == "false" || active == undefined) ? false : true,
|
||||
title: {
|
||||
contains: (judul == undefined || judul == null) ? "" : judul,
|
||||
mode: "insensitive"
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.bannerImage.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan banner", data }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan data banner, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
99
src/app/api/ai/calendar/[id]/route.ts
Normal file
99
src/app/api/ai/calendar/[id]/route.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// GET ONE CALENDER BY ID KALENDER REMINDER
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params
|
||||
|
||||
const cek = await prisma.divisionCalendarReminder.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (cek == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Gagal mendapatkan acara, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const data: any = await prisma.divisionCalendarReminder.findUnique({
|
||||
where: {
|
||||
id: id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
timeStart: true,
|
||||
dateStart: true,
|
||||
timeEnd: true,
|
||||
createdAt: true,
|
||||
DivisionCalendar: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
linkMeet: true,
|
||||
repeatEventTyper: true,
|
||||
repeatValue: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { DivisionCalendar, ...dataCalender } = data
|
||||
const timeStart = moment.utc(dataCalender?.timeStart).format("HH:mm")
|
||||
const timeEnd = moment.utc(dataCalender?.timeEnd).format("HH:mm")
|
||||
const idCalendar = data?.DivisionCalendar.id
|
||||
const title = data?.DivisionCalendar?.title
|
||||
const desc = data?.DivisionCalendar?.desc
|
||||
const linkMeet = data?.DivisionCalendar?.linkMeet
|
||||
const repeatEventTyper = data?.DivisionCalendar?.repeatEventTyper
|
||||
const repeatValue = data?.DivisionCalendar?.repeatValue
|
||||
|
||||
|
||||
const result = { ...dataCalender, timeStart, timeEnd, title, desc, linkMeet, repeatEventTyper, repeatValue }
|
||||
|
||||
|
||||
const member = await prisma.divisionCalendarMember.findMany({
|
||||
where: {
|
||||
idCalendar
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
img: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const fixMember = member.map((v: any) => ({
|
||||
..._.omit(v, ["User"]),
|
||||
name: v.User.name,
|
||||
email: v.User.email,
|
||||
img: v.User.img
|
||||
}))
|
||||
|
||||
|
||||
const dataFix = {
|
||||
...result,
|
||||
member: fixMember,
|
||||
}
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kalender", data: dataFix }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kalender, data tidak ditemukan (error: 500)", }, { status: 500 });
|
||||
}
|
||||
}
|
||||
149
src/app/api/ai/calendar/route.ts
Normal file
149
src/app/api/ai/calendar/route.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import "moment/locale/id";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
//GET ALL CALENDER
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idDivision = searchParams.get("division");
|
||||
const isDate = searchParams.get("date")
|
||||
const villageId = searchParams.get("desa")
|
||||
const active = searchParams.get("active")
|
||||
const search = searchParams.get("search")
|
||||
const page = searchParams.get("page")
|
||||
const get = searchParams.get("get")
|
||||
|
||||
let getFix = 0;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
|
||||
let kondisi: any = {}
|
||||
|
||||
if (idDivision != "" && idDivision != null && idDivision != undefined) {
|
||||
if (isDate != null && isDate != undefined && isDate != "") {
|
||||
kondisi = {
|
||||
idDivision: String(idDivision),
|
||||
dateStart: new Date(String(isDate)),
|
||||
DivisionCalendar: {
|
||||
title: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
isActive: (active == "false" || active == undefined) ? false : true,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
idDivision: String(idDivision),
|
||||
DivisionCalendar: {
|
||||
title: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
isActive: (active == "false" || active == undefined) ? false : true,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isDate != null && isDate != undefined && isDate != "") {
|
||||
kondisi = {
|
||||
dateStart: new Date(String(isDate)),
|
||||
DivisionCalendar: {
|
||||
title: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
isActive: (active == "false" || active == undefined) ? false : true,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
DivisionCalendar: {
|
||||
title: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
isActive: (active == "false" || active == undefined) ? false : true,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.divisionCalendarReminder.findMany({
|
||||
where: kondisi,
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
select: {
|
||||
id: true,
|
||||
dateStart: true,
|
||||
timeStart: true,
|
||||
timeEnd: true,
|
||||
createdAt: true,
|
||||
DivisionCalendar: {
|
||||
select: {
|
||||
isActive: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
dateStart: 'asc'
|
||||
},
|
||||
{
|
||||
timeStart: 'asc'
|
||||
},
|
||||
{
|
||||
timeEnd: 'asc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const allOmit = data.map((v: any) => ({
|
||||
..._.omit(v, ["DivisionCalendar", "User"]),
|
||||
title: v.DivisionCalendar.title,
|
||||
desc: v.DivisionCalendar.desc,
|
||||
createdBy: v.DivisionCalendar.User.name,
|
||||
isActive: v.DivisionCalendar.isActive,
|
||||
timeStart: moment.utc(v.timeStart).format('HH:mm'),
|
||||
timeEnd: moment.utc(v.timeEnd).format('HH:mm')
|
||||
}))
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kalender", data: allOmit }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kalender, data tidak ditemukan (error: 500)" }, { status: 404 });
|
||||
}
|
||||
}
|
||||
117
src/app/api/ai/discussion-general/[id]/route.ts
Normal file
117
src/app/api/ai/discussion-general/[id]/route.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ONE DETAIL DISKUSI UMUM
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
let dataFix
|
||||
const { id } = context.params
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const kategori = searchParams.get("cat");
|
||||
const idVillage = searchParams.get("desa");
|
||||
|
||||
const cek = await prisma.discussion.count({
|
||||
where: {
|
||||
id,
|
||||
idVillage: String(idVillage)
|
||||
}
|
||||
})
|
||||
|
||||
if (cek == 0) {
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 404 });
|
||||
}
|
||||
|
||||
if (kategori == "comment") {
|
||||
const data = await prisma.discussionComment.findMany({
|
||||
where: {
|
||||
idDiscussion: id,
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
comment: true,
|
||||
createdAt: true,
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true,
|
||||
img: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
dataFix = data.map((v: any) => ({
|
||||
..._.omit(v, ["User",]),
|
||||
username: v.User.name,
|
||||
img: v.User.img
|
||||
}))
|
||||
|
||||
} else if (kategori == "member") {
|
||||
const data = await prisma.discussionMember.findMany({
|
||||
where: {
|
||||
idDiscussion: id,
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true,
|
||||
img: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
dataFix = data.map((v: any) => ({
|
||||
..._.omit(v, ["User",]),
|
||||
name: v.User.name,
|
||||
img: v.User.img
|
||||
}))
|
||||
} else {
|
||||
const data = await prisma.discussion.findUnique({
|
||||
where: {
|
||||
id,
|
||||
idVillage: String(idVillage)
|
||||
},
|
||||
select: {
|
||||
isActive: true,
|
||||
id: true,
|
||||
title: true,
|
||||
idGroup: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
Group: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
dataFix = {
|
||||
id: data?.id,
|
||||
isActive: data?.isActive,
|
||||
idGroup: data?.idGroup,
|
||||
group: data?.Group.name,
|
||||
title: data?.title,
|
||||
desc: data?.desc,
|
||||
status: data?.status == 1 ? "Open" : "Close",
|
||||
createdAt: data?.createdAt
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan diskusi", data: dataFix }, { status: 200 });
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
92
src/app/api/ai/discussion-general/route.ts
Normal file
92
src/app/api/ai/discussion-general/route.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import "moment/locale/id";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL DISCUSSION GENERAL
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idGroup = searchParams.get("group");
|
||||
const idVillage = searchParams.get("desa");
|
||||
const search = searchParams.get('search');
|
||||
const page = searchParams.get('page');
|
||||
const status = searchParams.get('status');
|
||||
const active = searchParams.get('active');
|
||||
const get = searchParams.get('get')
|
||||
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: active == "false" ? false : true,
|
||||
status: status == "close" ? 2 : 1,
|
||||
idVillage: String(idVillage),
|
||||
title: {
|
||||
contains: (search == undefined || search == "null") ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
}
|
||||
|
||||
if (idGroup != "null" && idGroup != undefined && idGroup != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idGroup: String(idGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const data = await prisma.discussion.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
orderBy: [
|
||||
{
|
||||
status: 'desc'
|
||||
},
|
||||
{
|
||||
createdAt: 'desc'
|
||||
}
|
||||
],
|
||||
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
DiscussionComment: {
|
||||
select: {
|
||||
id: true,
|
||||
}
|
||||
},
|
||||
Group: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const fixData = data.map((v: any) => ({
|
||||
..._.omit(v, ["DiscussionComment", "status", "Group"]),
|
||||
totalKomentar: v.DiscussionComment.length,
|
||||
status: v.status == 1 ? "Open" : "Close",
|
||||
group: v.Group.name,
|
||||
}))
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan diskusi", data: fixData }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
92
src/app/api/ai/discussion/[id]/route.ts
Normal file
92
src/app/api/ai/discussion/[id]/route.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// GET ONE DISCUSSION BY ID
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params
|
||||
|
||||
const cek = await prisma.divisionDisscussion.count({
|
||||
where: { id }
|
||||
})
|
||||
|
||||
if (cek == 0) {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const data = await prisma.divisionDisscussion.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
isActive: true,
|
||||
id: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
idDivision: true,
|
||||
Division: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
},
|
||||
User: { select: { name: true, img: true } },
|
||||
DivisionDisscussionComment: {
|
||||
select: {
|
||||
id: true,
|
||||
comment: true,
|
||||
createdAt: true,
|
||||
User: { select: { name: true, img: true } }
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: "Diskusi tidak ditemukan" },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
// ambil nama creator
|
||||
const createdBy = data.User.name;
|
||||
const status = data.status == 1 ? "Open" : "Close"
|
||||
const division = data.Division.name
|
||||
|
||||
// mapping komentar → hilangkan nested User
|
||||
const komentar = data.DivisionDisscussionComment.map((comment: any) => ({
|
||||
id: comment.id,
|
||||
comment: comment.comment,
|
||||
createdAt: comment.createdAt,
|
||||
username: comment.User.name,
|
||||
userimg: comment.User.img,
|
||||
}));
|
||||
|
||||
// bentuk hasil akhir sesuai request
|
||||
const result = {
|
||||
id: data.id,
|
||||
idDivision: data.idDivision,
|
||||
division,
|
||||
isActive: data.isActive,
|
||||
desc: data.desc,
|
||||
status,
|
||||
createdAt: data.createdAt,
|
||||
createdBy,
|
||||
komentar,
|
||||
};
|
||||
|
||||
return NextResponse.json(
|
||||
{ success: true, message: "Berhasil mendapatkan diskusi", data: result },
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json(
|
||||
{ success: false, message: "Gagal mendapatkan diskusi, coba lagi nanti (error: 500)", reason: (error as Error).message },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
95
src/app/api/ai/discussion/route.ts
Normal file
95
src/app/api/ai/discussion/route.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import "moment/locale/id";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL DISCUSSION DIVISION ACTIVE = TRUE
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idDivision = searchParams.get("division");
|
||||
const search = searchParams.get('search');
|
||||
const page = searchParams.get('page');
|
||||
const status = searchParams.get('status');
|
||||
const isActive = searchParams.get('active');
|
||||
const villageId = searchParams.get('desa');
|
||||
const get = searchParams.get('get');
|
||||
|
||||
let getFix = 0;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: isActive == "false" ? false : true,
|
||||
status: status == "close" ? 2 : 1,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
},
|
||||
desc: {
|
||||
contains: (search == undefined || search == "null") ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
if (idDivision != "null" && idDivision != null && idDivision != undefined) {
|
||||
kondisi = {
|
||||
isActive: isActive == "false" ? false : true,
|
||||
status: status == "close" ? 2 : 1,
|
||||
idDivision: idDivision,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
},
|
||||
desc: {
|
||||
contains: (search == undefined || search == "null") ? "" : search,
|
||||
mode: "insensitive"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.divisionDisscussion.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
idDivision: true,
|
||||
Division: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
},
|
||||
DivisionDisscussionComment: {
|
||||
select: {
|
||||
id: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const fixData = data.map((v: any) => ({
|
||||
..._.omit(v, ["DivisionDisscussionComment", "status", "Division"]),
|
||||
totalKomentar: v.DivisionDisscussionComment.length,
|
||||
status: v.status == 1 ? "Open" : "Close",
|
||||
division: v.Division.name
|
||||
}))
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan diskusi", data: fixData, }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
63
src/app/api/ai/division/[id]/route.ts
Normal file
63
src/app/api/ai/division/[id]/route.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ONE DATA DIVISI :: UNTUK TAMPIL DATA DI HALAMAN EDIT DAN INFO
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idVillage = searchParams.get("desa");
|
||||
|
||||
const data = await prisma.division.findUnique({
|
||||
where: {
|
||||
id: String(id),
|
||||
idVillage: String(idVillage)
|
||||
}
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan", }, { status: 404 });
|
||||
}
|
||||
|
||||
const member = await prisma.divisionMember.findMany({
|
||||
where: {
|
||||
idDivision: String(id),
|
||||
isActive: true,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
isAdmin: true,
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true,
|
||||
img: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
isAdmin: 'desc',
|
||||
}
|
||||
})
|
||||
|
||||
const fixMember = member.map((v: any) => ({
|
||||
..._.omit(v, ["User"]),
|
||||
name: v.User.name,
|
||||
img: v.User.img
|
||||
}))
|
||||
|
||||
const dataFix = {
|
||||
...data,
|
||||
member: fixMember
|
||||
}
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data: dataFix, }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
269
src/app/api/ai/division/report/route.ts
Normal file
269
src/app/api/ai/division/report/route.ts
Normal file
@@ -0,0 +1,269 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const idVillage = searchParams.get("desa")
|
||||
const idGroup = searchParams.get("group")
|
||||
const division = searchParams.get("division")
|
||||
const date = searchParams.get("date-start")
|
||||
const dateAkhir = searchParams.get("date-end")
|
||||
const kat = searchParams.get("cat")
|
||||
|
||||
|
||||
// CHART PROGRESS
|
||||
if (kat == "dokumen") {
|
||||
// CHART DOKUMEN
|
||||
let kondisi: any = {
|
||||
isActive: true,
|
||||
category: 'FILE',
|
||||
Division: {
|
||||
idVillage: String(idVillage)
|
||||
},
|
||||
createdAt: {
|
||||
gte: new Date(String(date)),
|
||||
lte: new Date(String(dateAkhir))
|
||||
},
|
||||
}
|
||||
|
||||
if (idGroup != undefined && idGroup != null && idGroup != "") {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
category: 'FILE',
|
||||
Division: {
|
||||
idGroup: String(idGroup)
|
||||
},
|
||||
createdAt: {
|
||||
gte: new Date(String(date)),
|
||||
lte: new Date(String(dateAkhir))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (division != undefined && division != null && division != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idDivision: String(division)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const dataDokumen = await prisma.divisionDocumentFolderFile.findMany({
|
||||
where: kondisi,
|
||||
})
|
||||
|
||||
const groupData = _.map(_.groupBy(dataDokumen, "extension"), (v: any) => ({
|
||||
file: v[0].extension,
|
||||
jumlah: v.length,
|
||||
}))
|
||||
|
||||
const image = ['jpg', 'jpeg', 'png', 'heic']
|
||||
|
||||
let hasilImage = {
|
||||
name: 'Gambar',
|
||||
value: 0
|
||||
}
|
||||
|
||||
let hasilFile = {
|
||||
name: 'Dokumen',
|
||||
value: 0
|
||||
}
|
||||
|
||||
groupData.map((v: any) => {
|
||||
if (image.some((i: any) => i == v.file)) {
|
||||
hasilImage = {
|
||||
name: 'Gambar',
|
||||
value: hasilImage.value + v.jumlah
|
||||
}
|
||||
} else {
|
||||
hasilFile = {
|
||||
name: 'Dokumen',
|
||||
value: hasilFile.value + v.jumlah
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const hasilDokumen = { gambar: hasilImage.value, dokumen: hasilFile.value }
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: hasilDokumen }, { status: 200 });
|
||||
} else if (kat == "event") {
|
||||
// CHART EVENT
|
||||
let kondisiSelesai: any = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idVillage: String(idVillage)
|
||||
},
|
||||
DivisionCalendarReminder: {
|
||||
some: {
|
||||
dateStart: {
|
||||
gte: new Date(String(date)),
|
||||
lte: new Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let kondisiComingSoon: any = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idVillage: String(idVillage)
|
||||
},
|
||||
DivisionCalendarReminder: {
|
||||
some: {
|
||||
dateStart: {
|
||||
gt: new Date(),
|
||||
lte: new Date(String(dateAkhir))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idGroup != undefined && idGroup != null && idGroup != "") {
|
||||
kondisiSelesai = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idGroup: String(idGroup)
|
||||
},
|
||||
DivisionCalendarReminder: {
|
||||
some: {
|
||||
dateStart: {
|
||||
gte: new Date(String(date)),
|
||||
lte: new Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kondisiComingSoon = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idGroup: String(idGroup)
|
||||
},
|
||||
DivisionCalendarReminder: {
|
||||
some: {
|
||||
dateStart: {
|
||||
gt: new Date(),
|
||||
lte: new Date(String(dateAkhir))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (division != undefined && division != null && division != "") {
|
||||
kondisiSelesai = {
|
||||
...kondisiSelesai,
|
||||
idDivision: String(division)
|
||||
}
|
||||
|
||||
kondisiComingSoon = {
|
||||
...kondisiComingSoon,
|
||||
idDivision: String(division)
|
||||
}
|
||||
}
|
||||
|
||||
const eventSelesai = await prisma.divisionCalendar.count({
|
||||
where: kondisiSelesai
|
||||
})
|
||||
|
||||
const eventComingSoon = await prisma.divisionCalendar.count({
|
||||
where: kondisiComingSoon
|
||||
})
|
||||
|
||||
const hasilEvent = {
|
||||
selesai: eventSelesai,
|
||||
akan_datang: eventComingSoon
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: hasilEvent }, { status: 200 });
|
||||
|
||||
} else {
|
||||
let kondisiProgress: any = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idVillage: String(idVillage)
|
||||
},
|
||||
DivisionProjectTask: {
|
||||
some: {
|
||||
dateStart: {
|
||||
gte: new Date(String(date))
|
||||
},
|
||||
dateEnd: {
|
||||
lte: new Date(String(dateAkhir))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idGroup != undefined && idGroup != null && idGroup != "") {
|
||||
kondisiProgress = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idGroup: String(idGroup)
|
||||
},
|
||||
DivisionProjectTask: {
|
||||
some: {
|
||||
dateStart: {
|
||||
gte: new Date(String(date))
|
||||
},
|
||||
dateEnd: {
|
||||
lte: new Date(String(dateAkhir))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (division != undefined && division != null && division != "") {
|
||||
kondisiProgress = {
|
||||
...kondisiProgress,
|
||||
idDivision: String(division)
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.divisionProject.groupBy({
|
||||
where: kondisiProgress,
|
||||
by: ["status"],
|
||||
_count: true
|
||||
})
|
||||
|
||||
const dataStatus = [{ name: 'Segera', status: 0 }, { name: 'Dikerjakan', status: 1 }, { name: 'Selesai', status: 2 }, { name: 'Dibatalkan', status: 3 }]
|
||||
const hasilProgres: any[] = []
|
||||
let input
|
||||
for (let index = 0; index < dataStatus.length; index++) {
|
||||
const cek = data.some((i: any) => i.status == dataStatus[index].status)
|
||||
if (cek) {
|
||||
const find = ((Number(data.find((i: any) => i.status == dataStatus[index].status)?._count) * 100) / data.reduce((n, { _count }) => n + _count, 0)).toFixed(2)
|
||||
const fix = find != "100.00" ? find.substr(-2, 2) == "00" ? find.substr(0, 2) : find : "100"
|
||||
input = {
|
||||
name: dataStatus[index].name,
|
||||
value: fix
|
||||
}
|
||||
} else {
|
||||
input = {
|
||||
name: dataStatus[index].name,
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
hasilProgres.push(input)
|
||||
}
|
||||
|
||||
const dataFixProgress = hasilProgres.reduce((acc: any, curr: any) => {
|
||||
acc[curr.name] = curr.value
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: dataFixProgress }, { status: 200 });
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan data, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
84
src/app/api/ai/division/route.ts
Normal file
84
src/app/api/ai/division/route.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL DATA DIVISI == LIST DATA DIVISI
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idVillage = searchParams.get("desa");
|
||||
const idGroup = searchParams.get("group");
|
||||
const name = searchParams.get('search');
|
||||
const page = searchParams.get('page');
|
||||
const active = searchParams.get("active");
|
||||
const get = searchParams.get('get')
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: active == 'false' ? false : true,
|
||||
idVillage: String(idVillage),
|
||||
name: {
|
||||
contains: (name == undefined || name == "null") ? "" : name,
|
||||
mode: "insensitive"
|
||||
}
|
||||
}
|
||||
|
||||
if (idGroup != "null" && idGroup != undefined && idGroup != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idGroup: String(idGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const data = await prisma.division.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
desc: true,
|
||||
idGroup: true,
|
||||
Group: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
},
|
||||
DivisionMember: {
|
||||
where: {
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
idUser: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
const allData = data.map((v: any) => ({
|
||||
..._.omit(v, ["DivisionMember", "Group"]),
|
||||
group: v.Group.name,
|
||||
jumlahMember: v.DivisionMember.length,
|
||||
}))
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data: allData }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
145
src/app/api/ai/document/route.ts
Normal file
145
src/app/api/ai/document/route.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL DOCUMENT
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idDivision = searchParams.get("division");
|
||||
const villageId = searchParams.get("desa");
|
||||
const path = searchParams.get("path");
|
||||
const active = searchParams.get("active");
|
||||
const search = searchParams.get("search");
|
||||
const page = searchParams.get("page");
|
||||
const get = searchParams.get("get");
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
},
|
||||
isActive: active == 'false' ? false : true,
|
||||
path: (path == "undefined" || path == "null" || path == "" || path == null || path == undefined) ? "home" : path,
|
||||
name: {
|
||||
contains: (search == undefined || search == "null") ? "" : search,
|
||||
mode: "insensitive"
|
||||
}
|
||||
}
|
||||
|
||||
if (idDivision != "null" && idDivision != undefined && idDivision != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idDivision: String(idDivision)
|
||||
}
|
||||
}
|
||||
|
||||
let formatDataShare: any[] = [];
|
||||
|
||||
if (path == "home" || path == "null" || path == "undefined" || path == null || path == undefined || path == "") {
|
||||
const dataShare = await prisma.divisionDocumentShare.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idDivision: String(idDivision),
|
||||
DivisionDocumentFolderFile: {
|
||||
isActive: true
|
||||
}
|
||||
},
|
||||
select: {
|
||||
DivisionDocumentFolderFile: {
|
||||
select: {
|
||||
idStorage: true,
|
||||
id: true,
|
||||
category: true,
|
||||
name: true,
|
||||
extension: true,
|
||||
path: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
},
|
||||
createdAt: true,
|
||||
updatedAt: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
DivisionDocumentFolderFile: {
|
||||
createdAt: 'desc'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
formatDataShare = dataShare.map((v: any) => ({
|
||||
..._.omit(v, ["DivisionDocumentFolderFile"]),
|
||||
idStorage: v.DivisionDocumentFolderFile.idStorage,
|
||||
id: v.DivisionDocumentFolderFile.id,
|
||||
category: v.DivisionDocumentFolderFile.category,
|
||||
name: v.DivisionDocumentFolderFile.name,
|
||||
extension: v.DivisionDocumentFolderFile.extension,
|
||||
path: v.DivisionDocumentFolderFile.path,
|
||||
createdBy: v.DivisionDocumentFolderFile.User.name,
|
||||
createdAt: v.DivisionDocumentFolderFile.createdAt,
|
||||
updatedAt: v.DivisionDocumentFolderFile.updatedAt,
|
||||
share: true
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
const data = await prisma.divisionDocumentFolderFile.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
select: {
|
||||
id: true,
|
||||
category: true,
|
||||
name: true,
|
||||
extension: true,
|
||||
idStorage: true,
|
||||
path: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
},
|
||||
createdAt: true,
|
||||
updatedAt: true
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
const allData = data.map((v: any) => ({
|
||||
..._.omit(v, ["User", "createdAt", "updatedAt"]),
|
||||
createdBy: v.User.name,
|
||||
createdAt: v.createdAt,
|
||||
updatedAt: v.updatedAt,
|
||||
share: false
|
||||
}))
|
||||
|
||||
if (formatDataShare.length > 0) {
|
||||
allData.push(...formatDataShare)
|
||||
}
|
||||
|
||||
const formatData = _.orderBy(allData, ['category', 'createdAt'], ['desc', 'desc']);
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan item", data: formatData }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan item, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
45
src/app/api/ai/group/route.ts
Normal file
45
src/app/api/ai/group/route.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const villageId = searchParams.get("desa");
|
||||
const isActive = searchParams.get("active");
|
||||
const search = searchParams.get('search');
|
||||
const page = searchParams.get('page')
|
||||
const get = searchParams.get('get')
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
const data = await prisma.group.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: {
|
||||
isActive: isActive == 'false' ? false : true,
|
||||
idVillage: String(villageId),
|
||||
name: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan grup", data, }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan grup, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
79
src/app/api/ai/position/route.ts
Normal file
79
src/app/api/ai/position/route.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL POSITION
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idVillage = searchParams.get("desa");
|
||||
const idGroup = searchParams.get("group");
|
||||
const active = searchParams.get('active');
|
||||
const search = searchParams.get('search')
|
||||
const page = searchParams.get('page')
|
||||
const get = searchParams.get('get')
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: active == 'false' ? false : true,
|
||||
Group: {
|
||||
idVillage: String(idVillage)
|
||||
},
|
||||
name: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
}
|
||||
}
|
||||
|
||||
if (idGroup != "null" && idGroup != undefined && idGroup != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idGroup: String(idGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const positions = await prisma.position.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
idGroup: true,
|
||||
isActive: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
Group: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
const allData = positions.map((v: any) => ({
|
||||
..._.omit(v, ["Group"]),
|
||||
group: v.Group.name
|
||||
}))
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan jabatan", data: allData }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan jabatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
172
src/app/api/ai/project/[id]/route.ts
Normal file
172
src/app/api/ai/project/[id]/route.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET DETAIL PROJECT / GET ONE PROJECT
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
let allData
|
||||
const { id } = context.params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const kategori = searchParams.get("cat");
|
||||
|
||||
const data = await prisma.project.findUnique({
|
||||
where: {
|
||||
id: String(id),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
idVillage: true,
|
||||
idGroup: true,
|
||||
title: true,
|
||||
status: true,
|
||||
desc: true,
|
||||
reason: true,
|
||||
report: true,
|
||||
isActive: true,
|
||||
Group: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", }, { status: 404 });
|
||||
}
|
||||
|
||||
|
||||
if (kategori == "data") {
|
||||
const dataProgress = await prisma.projectTask.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
updatedAt: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
const semua = dataProgress.length
|
||||
const selesai = _.filter(dataProgress, { status: 1 }).length
|
||||
const progress = Math.ceil((selesai / semua) * 100)
|
||||
|
||||
allData = {
|
||||
id: data.id,
|
||||
idVillage: data.idVillage,
|
||||
idGroup: data.idGroup,
|
||||
group: data.Group.name,
|
||||
title: data.title,
|
||||
status: data.status == 3 ? "batal" : data.status == 2 ? "selesai" : data.status == 1 ? "dikerjakan" : "segera",
|
||||
desc: data.desc,
|
||||
reason: data.reason,
|
||||
report: data.report,
|
||||
isActive: data.isActive,
|
||||
progress: (_.isNaN(progress)) ? 0 : progress,
|
||||
}
|
||||
|
||||
} else if (kategori == "task") {
|
||||
const dataProgress = await prisma.projectTask.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
dateStart: true,
|
||||
dateEnd: true,
|
||||
createdAt: true
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
|
||||
const formatData = dataProgress.map((v: any) => ({
|
||||
..._.omit(v, ["dateStart", "dateEnd", "createdAt", "status"]),
|
||||
status: v.status == 1 ? "selesai" : "belum selesai",
|
||||
dateStart: moment(v.dateStart).format("DD-MM-YYYY"),
|
||||
dateEnd: moment(v.dateEnd).format("DD-MM-YYYY"),
|
||||
createdAt: moment(v.createdAt).format("DD-MM-YYYY HH:mm"),
|
||||
}))
|
||||
const dataFix = _.orderBy(formatData, 'createdAt', 'asc')
|
||||
allData = dataFix
|
||||
|
||||
} else if (kategori == "file") {
|
||||
const dataFile = await prisma.projectFile.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
extension: true,
|
||||
idStorage: true
|
||||
}
|
||||
})
|
||||
|
||||
allData = dataFile
|
||||
|
||||
} else if (kategori == "member") {
|
||||
const dataMember = await prisma.projectMember.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
img: true,
|
||||
Position: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const fix = dataMember.map((v: any) => ({
|
||||
..._.omit(v, ["User"]),
|
||||
name: v.User.name,
|
||||
email: v.User.email,
|
||||
img: v.User.img,
|
||||
position: v.User.Position.name
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
} else if (kategori == "link") {
|
||||
const dataLink = await prisma.projectLink.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
allData = dataLink
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: allData }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
107
src/app/api/ai/project/route.ts
Normal file
107
src/app/api/ai/project/route.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _, { ceil } from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL DATA PROJECT
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const idVillage = searchParams.get('desa');
|
||||
const name = searchParams.get('search');
|
||||
const status = searchParams.get('status');
|
||||
const idGroup = searchParams.get("group");
|
||||
const page = searchParams.get('page');
|
||||
const get = searchParams.get('get');
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
|
||||
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: true,
|
||||
idVillage: String(idVillage),
|
||||
title: {
|
||||
contains: (name == undefined || name == "null") ? "" : name,
|
||||
mode: "insensitive"
|
||||
},
|
||||
}
|
||||
|
||||
if (status != "null" && status != undefined && status != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
status: status == "segera" ? 0 : status == "dikerjakan" ? 1 : status == "selesai" ? 2 : status == "batal" ? 3 : 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (idGroup != "null" && idGroup != undefined && idGroup != "") {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idGroup: String(idGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const data = await prisma.project.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
select: {
|
||||
id: true,
|
||||
idGroup: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
ProjectMember: {
|
||||
where: {
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
idUser: true
|
||||
}
|
||||
},
|
||||
ProjectTask: {
|
||||
where: {
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
title: true,
|
||||
status: true
|
||||
}
|
||||
},
|
||||
Group: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
const omitData = data.map((v: any) => ({
|
||||
..._.omit(v, ["ProjectMember", "ProjectTask", "status", "Group"]),
|
||||
group: v.Group.name,
|
||||
status: v.status == 1 ? "dikerjakan" : v.status == 2 ? "selesai" : v.status == 3 ? "batal" : "segera",
|
||||
progress: ceil((v.ProjectTask.filter((i: any) => i.status == 1).length * 100) / v.ProjectTask.length),
|
||||
member: v.ProjectMember.length
|
||||
}))
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: omitData }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
180
src/app/api/ai/task/[id]/route.ts
Normal file
180
src/app/api/ai/task/[id]/route.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import "moment/locale/id";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET DETAIL TASK DIVISI / GET ONE
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
let allData
|
||||
const { id } = context.params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const kategori = searchParams.get("cat");
|
||||
|
||||
const data = await prisma.divisionProject.findUnique({
|
||||
where: {
|
||||
id: String(id),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
idDivision: true,
|
||||
title: true,
|
||||
status: true,
|
||||
desc: true,
|
||||
reason: true,
|
||||
report: true,
|
||||
isActive: true,
|
||||
Division: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", }, { status: 404 });
|
||||
}
|
||||
|
||||
if (kategori == "data") {
|
||||
const dataProgress = await prisma.divisionProjectTask.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
updatedAt: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
const semua = dataProgress.length
|
||||
const selesai = _.filter(dataProgress, { status: 1 }).length
|
||||
const progress = Math.ceil((selesai / semua) * 100)
|
||||
|
||||
|
||||
allData = {
|
||||
id: data.id,
|
||||
idDivision: data.idDivision,
|
||||
division: data.Division.name,
|
||||
title: data.title,
|
||||
status: data.status == 3 ? "batal" : data.status == 2 ? "selesai" : data.status == 1 ? "dikerjakan" : "segera",
|
||||
desc: data.desc,
|
||||
reason: data.reason,
|
||||
report: data.report,
|
||||
isActive: data.isActive,
|
||||
progress: progress,
|
||||
}
|
||||
} else if (kategori == "task") {
|
||||
const dataProgress = await prisma.divisionProjectTask.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
status: true,
|
||||
dateStart: true,
|
||||
dateEnd: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
|
||||
const fix = dataProgress.map((v: any) => ({
|
||||
..._.omit(v, ["dateStart", "dateEnd", "status"]),
|
||||
status: v.status == 1 ? "selesai" : "belum selesai",
|
||||
dateStart: moment(v.dateStart).format("DD-MM-YYYY"),
|
||||
dateEnd: moment(v.dateEnd).format("DD-MM-YYYY"),
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
|
||||
} else if (kategori == "file") {
|
||||
const dataFile = await prisma.divisionProjectFile.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
ContainerFileDivision: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
extension: true,
|
||||
idStorage: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const fix = dataFile.map((v: any) => ({
|
||||
..._.omit(v, ["ContainerFileDivision"]),
|
||||
nameInStorage: v.ContainerFileDivision.id,
|
||||
name: v.ContainerFileDivision.name,
|
||||
extension: v.ContainerFileDivision.extension,
|
||||
idStorage: v.ContainerFileDivision.idStorage,
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
|
||||
} else if (kategori == "member") {
|
||||
const dataMember = await prisma.divisionProjectMember.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
img: true,
|
||||
Position: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const fix = dataMember.map((v: any) => ({
|
||||
..._.omit(v, ["User"]),
|
||||
name: v.User.name,
|
||||
email: v.User.email,
|
||||
img: v.User.img,
|
||||
position: v.User.Position.name
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
} else if (kategori == "link") {
|
||||
const dataLink = await prisma.divisionProjectLink.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
|
||||
allData = dataLink
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan tugas divisi", data: allData }, { status: 200 });
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
104
src/app/api/ai/task/route.ts
Normal file
104
src/app/api/ai/task/route.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _, { ceil } from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
// GET ALL DATA TUGAS DIVISI
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const villageId = searchParams.get('desa');
|
||||
const division = searchParams.get('division');
|
||||
const search = searchParams.get('search');
|
||||
const status = searchParams.get('status');
|
||||
const page = searchParams.get('page');
|
||||
const get = searchParams.get('get');
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idVillage: String(villageId)
|
||||
},
|
||||
title: {
|
||||
contains: (search == undefined || search == "null") ? "" : search,
|
||||
mode: "insensitive"
|
||||
}
|
||||
}
|
||||
|
||||
if (status != "null" && status != undefined && status != "" && status != null) {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
status: status == "segera" ? 0 : status == "dikerjakan" ? 1 : status == "selesai" ? 2 : status == "batal" ? 3 : 0
|
||||
}
|
||||
}
|
||||
|
||||
if (division != "null" && division != undefined && division != "" && division != null) {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idDivision: String(division)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const data = await prisma.divisionProject.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
select: {
|
||||
id: true,
|
||||
idDivision: true,
|
||||
title: true,
|
||||
desc: true,
|
||||
status: true,
|
||||
DivisionProjectTask: {
|
||||
where: {
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
title: true,
|
||||
status: true
|
||||
}
|
||||
},
|
||||
DivisionProjectMember: {
|
||||
where: {
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
idUser: true
|
||||
}
|
||||
},
|
||||
Division: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc"
|
||||
}
|
||||
});
|
||||
|
||||
const formatData = data.map((v: any) => ({
|
||||
..._.omit(v, ["DivisionProjectTask", "DivisionProjectMember", "status", "Division"]),
|
||||
division: v.Division.name,
|
||||
status: v.status == 1 ? "dikerjakan" : v.status == 2 ? "selesai" : v.status == 3 ? "batal" : "segera",
|
||||
progress: ceil((v.DivisionProjectTask.filter((i: any) => i.status == 1).length * 100) / v.DivisionProjectTask.length),
|
||||
member: v.DivisionProjectMember.length,
|
||||
}))
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data: formatData }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
75
src/app/api/ai/user/[id]/route.ts
Normal file
75
src/app/api/ai/user/[id]/route.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// GET ONE MEMBER / USER
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
|
||||
const users = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
nik: true,
|
||||
name: true,
|
||||
phone: true,
|
||||
email: true,
|
||||
gender: true,
|
||||
img: true,
|
||||
idGroup: true,
|
||||
isActive: true,
|
||||
idPosition: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
UserRole: {
|
||||
select: {
|
||||
name: true,
|
||||
id: true
|
||||
}
|
||||
},
|
||||
Position: {
|
||||
select: {
|
||||
name: true,
|
||||
id: true
|
||||
},
|
||||
},
|
||||
Group: {
|
||||
select: {
|
||||
name: true,
|
||||
id: true
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { ...userData } = users;
|
||||
const group = users?.Group.name
|
||||
const position = users?.Position?.name
|
||||
const idUserRole = users?.UserRole.id
|
||||
const phone = '+62' + users?.phone
|
||||
const role = users?.UserRole.name
|
||||
const gender = users?.gender == "F" ? "Perempuan" : "Laki-Laki"
|
||||
|
||||
const result = { ...userData, gender, group, position, idUserRole, phone, role };
|
||||
|
||||
const omitData = _.omit(result, ["Group", "Position", "UserRole"]);
|
||||
|
||||
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: true,
|
||||
message: "Berhasil mendapatkan anggota",
|
||||
data: omitData,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan anggota, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
88
src/app/api/ai/user/route.ts
Normal file
88
src/app/api/ai/user/route.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// GET ALL MEMBER / USER
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const search = searchParams.get('search')
|
||||
const idVillage = searchParams.get("desa");
|
||||
const idGroup = searchParams.get("group");
|
||||
const active = searchParams.get("active");
|
||||
const page = searchParams.get('page');
|
||||
const get = searchParams.get('get');
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
let kondisi: any = {
|
||||
isActive: active == 'false' ? false : true,
|
||||
idVillage: String(idVillage),
|
||||
name: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive",
|
||||
},
|
||||
NOT: {
|
||||
idUserRole: 'developer'
|
||||
}
|
||||
}
|
||||
|
||||
if (idGroup != "null" && idGroup != undefined && idGroup != "" && idGroup != null) {
|
||||
kondisi = {
|
||||
...kondisi,
|
||||
idGroup: String(idGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: kondisi,
|
||||
select: {
|
||||
id: true,
|
||||
idUserRole: true,
|
||||
isActive: true,
|
||||
nik: true,
|
||||
name: true,
|
||||
phone: true,
|
||||
Position: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
Group: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
const allData = users.map((v: any) => ({
|
||||
..._.omit(v, ["phone", "gender", "Group", "Position"]),
|
||||
gender: v.gender == "F" ? "Perempuan" : "Laki-Laki",
|
||||
phone: "+" + v.phone,
|
||||
group: v.Group.name,
|
||||
position: v?.Position?.name
|
||||
}))
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil member", data: allData }, { status: 200 });
|
||||
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan anggota, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
50
src/app/api/ai/village/route.ts
Normal file
50
src/app/api/ai/village/route.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const isActive = searchParams.get("active");
|
||||
const search = searchParams.get('search');
|
||||
const page = searchParams.get('page')
|
||||
const get = searchParams.get('get')
|
||||
|
||||
let getFix = 10;
|
||||
if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) {
|
||||
getFix = 10;
|
||||
} else {
|
||||
getFix = Number(get);
|
||||
}
|
||||
|
||||
const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix;
|
||||
|
||||
const data = await prisma.village.findMany({
|
||||
skip: dataSkip,
|
||||
take: getFix,
|
||||
where: {
|
||||
isActive: isActive == 'false' ? false : true,
|
||||
name: {
|
||||
contains: (search == undefined || search == null) ? "" : search,
|
||||
mode: "insensitive"
|
||||
}
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
isActive: true,
|
||||
createdAt: true,
|
||||
updatedAt: true
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan desa", data, }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan desa, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ export async function POST(request: Request) {
|
||||
category: 'announcement',
|
||||
idContent: data.id,
|
||||
title: 'Pengumuman Baru',
|
||||
desc: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const dataPush = memberNotif.map((v: any) => ({
|
||||
@@ -217,7 +217,7 @@ export async function POST(request: Request) {
|
||||
category: 'announcement',
|
||||
idContent: data.id,
|
||||
title: 'Pengumuman Baru',
|
||||
desc: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -229,7 +229,7 @@ export async function POST(request: Request) {
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Pengumuman Baru', body: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Pengumuman Baru', body: title } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ export async function POST(req: NextRequest) {
|
||||
const { phone }: ILogin = await req.json();
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { phone, isActive: true },
|
||||
select: { id: true, phone: true },
|
||||
select: { id: true, phone: true, isWithoutOTP: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
@@ -21,6 +21,7 @@ export async function POST(req: NextRequest) {
|
||||
success: true,
|
||||
message: "Sukses",
|
||||
phone: user.phone,
|
||||
isWithoutOTP: user.isWithoutOTP,
|
||||
id: user.id,
|
||||
});
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ export async function POST(request: Request) {
|
||||
category: 'discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Umum Baru',
|
||||
desc: 'Terdapat diskusi umum baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
if (userRoleLogin != "supadmin") {
|
||||
@@ -173,7 +173,7 @@ export async function POST(request: Request) {
|
||||
category: 'discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Umum Baru',
|
||||
desc: 'Terdapat diskusi umum baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,8 @@ export async function POST(request: Request) {
|
||||
}
|
||||
})
|
||||
|
||||
const descNotif = desc.length > 300 ? desc.substring(0, 300) + '...' : desc
|
||||
|
||||
|
||||
// mengirim notifikasi
|
||||
// datanotif untuk realtime notifikasi
|
||||
@@ -157,7 +159,7 @@ export async function POST(request: Request) {
|
||||
category: 'division/' + idDivision + '/discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Baru',
|
||||
desc: 'Terdapat diskusi baru. Silahkan periksa detailnya.'
|
||||
desc: descNotif
|
||||
}))
|
||||
|
||||
const dataPush = memberDivision.map((v: any) => ({
|
||||
@@ -189,7 +191,7 @@ export async function POST(request: Request) {
|
||||
category: 'division/' + idDivision + '/discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Baru',
|
||||
desc: 'Terdapat diskusi baru. Silahkan periksa detailnya.'
|
||||
desc: descNotif
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -221,7 +223,7 @@ export async function POST(request: Request) {
|
||||
category: 'division/' + idDivision + '/discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Baru',
|
||||
desc: 'Terdapat diskusi baru. Silahkan periksa detailnya.'
|
||||
desc: descNotif
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -232,7 +234,7 @@ export async function POST(request: Request) {
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat diskusi baru. Silahkan periksa detailnya.', title: 'Diskusi Baru' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: descNotif, title: 'Diskusi Baru' } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
})
|
||||
|
||||
@@ -174,7 +174,7 @@ export async function POST(request: Request) {
|
||||
category: 'division',
|
||||
idContent: data.id,
|
||||
title: 'Divisi Baru',
|
||||
desc: 'Terdapat divisi baru. Silahkan periksa detailnya.'
|
||||
desc: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`
|
||||
}))
|
||||
|
||||
const selectUser = await prisma.divisionMember.findMany({
|
||||
@@ -225,7 +225,7 @@ export async function POST(request: Request) {
|
||||
category: 'division',
|
||||
idContent: data.id,
|
||||
title: 'Divisi Baru',
|
||||
desc: 'Terdapat divisi baru. Silahkan periksa detailnya.'
|
||||
desc: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -262,7 +262,7 @@ export async function POST(request: Request) {
|
||||
category: 'division',
|
||||
idContent: data.id,
|
||||
title: 'Divisi Baru',
|
||||
desc: 'Terdapat divisi baru. Silahkan periksa detailnya.'
|
||||
desc: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`
|
||||
}))
|
||||
|
||||
const omitPush = atasanGroup.map((v: any) => ({
|
||||
@@ -279,7 +279,7 @@ export async function POST(request: Request) {
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Divisi Baru', body: 'Terdapat divisi baru. Silahkan periksa detailnya.' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Divisi Baru', body: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.` } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
})
|
||||
|
||||
@@ -203,7 +203,7 @@ export async function POST(request: Request) {
|
||||
category: 'announcement',
|
||||
idContent: data.id,
|
||||
title: 'Pengumuman Baru',
|
||||
desc: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ export async function POST(request: Request) {
|
||||
category: 'announcement',
|
||||
idContent: data.id,
|
||||
title: 'Pengumuman Baru',
|
||||
desc: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -254,19 +254,20 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
|
||||
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Pengumuman Baru', body: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Pengumuman Baru', body: title } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
data: dataNotifFilter
|
||||
})
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())];
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Pengumuman Baru",
|
||||
body: "Anda memiliki pengumuman baru. Silahkan periksa detailnya.",
|
||||
body: title,
|
||||
data: { id: data.id, category: "announcement", content: data.id }
|
||||
})
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function POST(request: Request) {
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'LOGIN', desc: 'User login', table: 'user', data: '', user: userMobile.id })
|
||||
|
||||
if (cek == 0) {
|
||||
if (cek == 0 && token != "" && token != undefined && token != null) {
|
||||
const data = await prisma.tokenDeviceUser.create({
|
||||
data: {
|
||||
token,
|
||||
@@ -50,12 +50,15 @@ export async function PUT(request: Request) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
const data = await prisma.tokenDeviceUser.deleteMany({
|
||||
where: {
|
||||
token,
|
||||
idUser: userMobile.id
|
||||
}
|
||||
});
|
||||
if (token != "" && token != undefined && token != null) {
|
||||
const data = await prisma.tokenDeviceUser.deleteMany({
|
||||
where: {
|
||||
token,
|
||||
idUser: userMobile.id
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'LOGOUT', desc: 'User logout', table: 'user', data: '', user: userMobile.id })
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserById } from "@/module/auth";
|
||||
import { createLogUserMobile } from "@/module/user";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
import { sendFCMNotificationMany } from "../../../../../../../xsendMany";
|
||||
|
||||
|
||||
// KIRIM KOMENTAR DISKUSI UMUM
|
||||
@@ -35,6 +37,82 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
})
|
||||
|
||||
const member = await prisma.discussionMember.findMany({
|
||||
where: {
|
||||
idDiscussion: id,
|
||||
},
|
||||
select: {
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
Subscribe: {
|
||||
select: {
|
||||
subscription: true
|
||||
}
|
||||
},
|
||||
TokenDeviceUser: {
|
||||
select: {
|
||||
token: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const userSent = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: userMobile.id
|
||||
},
|
||||
select: {
|
||||
name: true,
|
||||
img: true
|
||||
}
|
||||
})
|
||||
|
||||
const memberFilter = member.filter((v: any) => v.idUser != userMobile.id)
|
||||
|
||||
const dataFCM = memberFilter.map((v: any) => ({
|
||||
..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]),
|
||||
tokens: v.User.TokenDeviceUser.map((v: any) => v.token)
|
||||
}))
|
||||
const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat();
|
||||
|
||||
if (userMobile.idUserRole != "supadmin") {
|
||||
const perbekel = await prisma.user.findFirst({
|
||||
where: {
|
||||
isActive: true,
|
||||
idUserRole: "supadmin",
|
||||
idVillage: userMobile.idVillage
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
Subscribe: {
|
||||
select: {
|
||||
subscription: true
|
||||
}
|
||||
},
|
||||
TokenDeviceUser: {
|
||||
select: {
|
||||
token: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat())
|
||||
}
|
||||
|
||||
const commentNotif = data.comment.length > 300 ? data.comment.substring(0, 300) + '...' : data.comment;
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Komentar Baru",
|
||||
body: `${userSent?.name}: ${commentNotif}`,
|
||||
data: { id: data.id, category: "discussion-general", content: id }
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User menambah komentar pada diskusi umum', table: 'discussionComment', data: data.id, user: userMobile.id })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menambah komentar" }, { status: 200 });
|
||||
|
||||
@@ -172,7 +172,7 @@ export async function POST(request: Request) {
|
||||
category: 'discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Umum Baru',
|
||||
desc: 'Terdapat diskusi umum baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
if (userRoleLogin != "supadmin") {
|
||||
@@ -205,19 +205,21 @@ export async function POST(request: Request) {
|
||||
category: 'discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Umum Baru',
|
||||
desc: 'Terdapat diskusi umum baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
})
|
||||
}
|
||||
|
||||
dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
|
||||
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
})
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())];
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Diskusi Umum Baru",
|
||||
body: "Anda memiliki diskusi umum baru. Silahkan periksa detailnya.",
|
||||
body: title,
|
||||
data: { id: data.id, category: "discussion", content: data.id }
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserById } from "@/module/auth";
|
||||
import { createLogUserMobile } from "@/module/user";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
import { sendFCMNotificationMany } from "../../../../../../../xsendMany";
|
||||
|
||||
// CREATE COMENT BY ID KOMENTAR
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
@@ -38,10 +40,95 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
createdBy: userMobile.id
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
id: true,
|
||||
}
|
||||
})
|
||||
|
||||
const dataDivision = await prisma.divisionDisscussion.findUnique({
|
||||
where: {
|
||||
id: id
|
||||
},
|
||||
select: {
|
||||
idDivision: true,
|
||||
}
|
||||
})
|
||||
|
||||
const member = await prisma.divisionMember.findMany({
|
||||
where: {
|
||||
idDivision: dataDivision?.idDivision
|
||||
},
|
||||
select: {
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
Subscribe: {
|
||||
select: {
|
||||
subscription: true
|
||||
}
|
||||
},
|
||||
TokenDeviceUser: {
|
||||
select: {
|
||||
token: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const userSent = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: userMobile.id
|
||||
},
|
||||
select: {
|
||||
name: true,
|
||||
img: true
|
||||
}
|
||||
})
|
||||
|
||||
const memberFilter = member.filter((v: any) => v.idUser != userMobile.id)
|
||||
|
||||
const dataFCM = memberFilter.map((v: any) => ({
|
||||
..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]),
|
||||
tokens: v.User.TokenDeviceUser.map((v: any) => v.token)
|
||||
}))
|
||||
|
||||
const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat();
|
||||
if (userMobile.idUserRole != "supadmin") {
|
||||
const perbekel = await prisma.user.findFirst({
|
||||
where: {
|
||||
isActive: true,
|
||||
idUserRole: "supadmin",
|
||||
idVillage: userMobile.idVillage
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
Subscribe: {
|
||||
select: {
|
||||
subscription: true
|
||||
}
|
||||
},
|
||||
TokenDeviceUser: {
|
||||
select: {
|
||||
token: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat())
|
||||
}
|
||||
|
||||
const commentNotif = comment.length > 300 ? comment.substring(0, 300) + '...' : comment;
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Komentar Baru",
|
||||
body: `${userSent?.name}: ${commentNotif}`,
|
||||
data: { id: data.id, category: `division/${dataDivision?.idDivision}/discussion`, content: id }
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User menambah komentar pada diskusi', table: 'divisionDisscussionComment', data: data.id, user: userMobile.id })
|
||||
|
||||
|
||||
@@ -155,6 +155,8 @@ export async function POST(request: Request) {
|
||||
}
|
||||
})
|
||||
|
||||
const deskripsiNotif = desc.length > 300 ? desc.substring(0, 300) + '...' : desc;
|
||||
|
||||
|
||||
// mengirim notifikasi
|
||||
// dataFCM untuk push notifikasi mobile
|
||||
@@ -173,7 +175,7 @@ export async function POST(request: Request) {
|
||||
category: 'division/' + idDivision + '/discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Baru',
|
||||
desc: 'Terdapat diskusi baru. Silahkan periksa detailnya.'
|
||||
desc: deskripsiNotif
|
||||
}))
|
||||
|
||||
const dataPush = memberDivision.map((v: any) => ({
|
||||
@@ -212,7 +214,7 @@ export async function POST(request: Request) {
|
||||
category: 'division/' + idDivision + '/discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Baru',
|
||||
desc: 'Terdapat diskusi baru. Silahkan periksa detailnya.'
|
||||
desc: deskripsiNotif
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -251,7 +253,7 @@ export async function POST(request: Request) {
|
||||
category: 'division/' + idDivision + '/discussion',
|
||||
idContent: data.id,
|
||||
title: 'Diskusi Baru',
|
||||
desc: 'Terdapat diskusi baru. Silahkan periksa detailnya.'
|
||||
desc: deskripsiNotif
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -260,19 +262,21 @@ export async function POST(request: Request) {
|
||||
})
|
||||
}
|
||||
|
||||
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat diskusi baru. Silahkan periksa detailnya.', title: 'Diskusi Baru' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: deskripsiNotif, title: 'Diskusi Baru' } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
data: dataNotifFilter
|
||||
})
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())];
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Diskusi Baru",
|
||||
body: "Anda memiliki diskusi baru. Silahkan periksa detailnya.",
|
||||
body: deskripsiNotif,
|
||||
data: { id: data.id, category: "division/" + idDivision + "/discussion", content: data.id }
|
||||
})
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ export async function POST(request: Request) {
|
||||
category: 'division',
|
||||
idContent: data.id,
|
||||
title: 'Divisi Baru',
|
||||
desc: 'Terdapat divisi baru. Silahkan periksa detailnya.'
|
||||
desc: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`
|
||||
}))
|
||||
|
||||
const selectUser = await prisma.divisionMember.findMany({
|
||||
@@ -252,7 +252,7 @@ export async function POST(request: Request) {
|
||||
category: 'division',
|
||||
idContent: data.id,
|
||||
title: 'Divisi Baru',
|
||||
desc: 'Terdapat divisi baru. Silahkan periksa detailnya.'
|
||||
desc: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -299,7 +299,7 @@ export async function POST(request: Request) {
|
||||
category: 'division',
|
||||
idContent: data.id,
|
||||
title: 'Divisi Baru',
|
||||
desc: 'Terdapat divisi baru. Silahkan periksa detailnya.'
|
||||
desc: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`
|
||||
}))
|
||||
|
||||
const omitPush = atasanGroup.map((v: any) => ({
|
||||
@@ -313,19 +313,20 @@ export async function POST(request: Request) {
|
||||
tokenDup.push(...omitFCM.map((v: any) => v.tokens).flat())
|
||||
}
|
||||
|
||||
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Divisi Baru', body: 'Terdapat divisi baru. Silahkan periksa detailnya.' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Divisi Baru', body: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.` } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
data: dataNotifFilter
|
||||
})
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())];
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Divisi Baru",
|
||||
body: "Anda memiliki divisi baru. Silahkan periksa detailnya.",
|
||||
body: `Divisi ${sent.data.name} telah dibuat. Silakan periksa detailnya.`,
|
||||
data: { id: data.id, category: "division", content: data.id }
|
||||
})
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.formData()
|
||||
const dataBody = body.get("data")
|
||||
const file = body.get("file") as File
|
||||
const fileName = file.name
|
||||
|
||||
const { idPath, idDivision, user } = JSON.parse(dataBody as string)
|
||||
|
||||
@@ -57,39 +55,48 @@ export async function POST(request: Request) {
|
||||
..._.omit(v, [""]),
|
||||
file: v.name + '.' + v.extension,
|
||||
}))
|
||||
|
||||
const cek = dataOmit.some((i: any) => i.file == fileName)
|
||||
|
||||
if (cek) {
|
||||
return NextResponse.json({ success: false, message: "Terdapat file dengan nama yang sama" }, { status: 200 });
|
||||
}
|
||||
|
||||
|
||||
const fExt = file.name.split(".").pop()
|
||||
const fName = file.name.replace("." + fExt, "")
|
||||
const upload = await funUploadFile({ file: file, dirId: DIR.document })
|
||||
if (upload.success) {
|
||||
const dataInsert = await prisma.divisionDocumentFolderFile.create({
|
||||
data: {
|
||||
name: fName,
|
||||
path: idPath,
|
||||
idDivision,
|
||||
category: "FILE",
|
||||
extension: String(fExt),
|
||||
createdBy: userMobile.id,
|
||||
idStorage: upload.data.id
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
let failed = 0
|
||||
body.delete("data")
|
||||
for (var pair of body.entries()) {
|
||||
if (String(pair[0]).substring(0, 4) == "file") {
|
||||
const file = body.get(pair[0]) as File
|
||||
const fileName = decodeURIComponent(file.name)
|
||||
const fExt = file.name.split(".").pop()
|
||||
let fName = fileName.replace("." + fExt, "")
|
||||
const cek = dataOmit.some((i: any) => i.file == fileName)
|
||||
if (cek) {
|
||||
const random = Math.floor(Math.random() * 1000)
|
||||
fName = `${fName}_${random}`
|
||||
}
|
||||
});
|
||||
const upload = await funUploadFile({ file: file, dirId: DIR.document })
|
||||
if (upload.success) {
|
||||
const dataInsert = await prisma.divisionDocumentFolderFile.create({
|
||||
data: {
|
||||
name: fName,
|
||||
path: idPath,
|
||||
idDivision,
|
||||
category: "FILE",
|
||||
extension: String(fExt),
|
||||
createdBy: userMobile.id,
|
||||
idStorage: upload.data.id
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
});
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User mengupload file baru', table: 'divisionDocumentFolderFile', data: dataInsert.id, user: userMobile.id })
|
||||
return NextResponse.json({ success: true, message: "Berhasil upload file" }, { status: 200 });
|
||||
} else {
|
||||
return NextResponse.json({ success: false, message: "Gagal upload file, coba lagi nanti" }, { status: 200 });
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User mengupload file baru', table: 'divisionDocumentFolderFile', data: dataInsert.id, user: userMobile.id })
|
||||
} else {
|
||||
failed++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (failed > 0) {
|
||||
return NextResponse.json({ success: false, message: "Beberapa file gagal diupload", failed }, { status: 200 });
|
||||
}
|
||||
return NextResponse.json({ success: true, message: "Berhasil upload file" }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal upload file, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
|
||||
@@ -37,22 +37,28 @@ export async function GET(request: Request) {
|
||||
isActive: true,
|
||||
}
|
||||
}
|
||||
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
idGroup: idGroup
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
idGroup: idGroup,
|
||||
ProjectMember: {
|
||||
some: {
|
||||
idUser: user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// idGroup: idGroup
|
||||
// }
|
||||
// } else {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// idGroup: idGroup,
|
||||
// ProjectMember: {
|
||||
// some: {
|
||||
// idUser: user.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const data = await prisma.project.findMany({
|
||||
skip: 0,
|
||||
@@ -97,24 +103,30 @@ export async function GET(request: Request) {
|
||||
isActive: true,
|
||||
}
|
||||
}
|
||||
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
idGroup: idGroup
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
idGroup: idGroup,
|
||||
DivisionMember: {
|
||||
some: {
|
||||
idUser: user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// idGroup: idGroup
|
||||
// }
|
||||
// } else {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// idGroup: idGroup,
|
||||
// DivisionMember: {
|
||||
// some: {
|
||||
// idUser: user.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
const data = await prisma.division.findMany({
|
||||
where: kondisi,
|
||||
select: {
|
||||
@@ -147,42 +159,63 @@ export async function GET(request: Request) {
|
||||
if (roleUser == "supadmin" || roleUser == "developer") {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
idVillage: idVillage,
|
||||
Group: {
|
||||
isActive: true,
|
||||
idVillage: idVillage,
|
||||
Group: {
|
||||
isActive: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
isActive: true,
|
||||
idGroup: idGroup
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
Division: {
|
||||
isActive: true,
|
||||
DivisionMember: {
|
||||
some: {
|
||||
idUser: user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
idGroup: idGroup
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.divisionProject.groupBy({
|
||||
// if (roleUser == "supadmin" || roleUser == "developer") {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// Division: {
|
||||
// isActive: true,
|
||||
// idVillage: idVillage,
|
||||
// Group: {
|
||||
// isActive: true,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// Division: {
|
||||
// isActive: true,
|
||||
// idGroup: idGroup
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// Division: {
|
||||
// isActive: true,
|
||||
// DivisionMember: {
|
||||
// some: {
|
||||
// idUser: user.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const data = await prisma.project.groupBy({
|
||||
where: kondisi,
|
||||
by: ["status"],
|
||||
_count: true
|
||||
})
|
||||
|
||||
// const data = await prisma.divisionProject.groupBy({
|
||||
// where: kondisi,
|
||||
// by: ["status"],
|
||||
// _count: true
|
||||
// })
|
||||
|
||||
const dataStatus = [{ name: 'Segera dikerjakan', status: 0, color: '#177AD5' }, { name: 'Dikerjakan', status: 1, color: '#fac858' }, { name: 'Selesai dikerjakan', status: 2, color: '#92cc76' }, { name: 'Dibatalkan', status: 3, color: '#ED6665' }]
|
||||
const hasil: any[] = []
|
||||
let input
|
||||
@@ -225,7 +258,7 @@ export async function GET(request: Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
category: 'FILE',
|
||||
@@ -234,21 +267,32 @@ export async function GET(request: Request) {
|
||||
idGroup: idGroup
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
category: 'FILE',
|
||||
Division: {
|
||||
isActive: true,
|
||||
DivisionMember: {
|
||||
some: {
|
||||
idUser: user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// category: 'FILE',
|
||||
// Division: {
|
||||
// isActive: true,
|
||||
// idGroup: idGroup
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// category: 'FILE',
|
||||
// Division: {
|
||||
// isActive: true,
|
||||
// DivisionMember: {
|
||||
// some: {
|
||||
// idUser: user.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const data = await prisma.divisionDocumentFolderFile.findMany({
|
||||
where: kondisi,
|
||||
})
|
||||
@@ -373,22 +417,34 @@ export async function GET(request: Request) {
|
||||
}))
|
||||
|
||||
} else if (kategori == "discussion") {
|
||||
let kondisi
|
||||
let kondisi, kondisiUmum
|
||||
|
||||
// klo perbekel/developer == semua grup
|
||||
if (roleUser == "supadmin" || roleUser == "developer") {
|
||||
kondisi = {
|
||||
kondisiUmum = {
|
||||
isActive: true,
|
||||
status: 1,
|
||||
Division: {
|
||||
idVillage: idVillage
|
||||
},
|
||||
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
idVillage: idVillage,
|
||||
Group: {
|
||||
status: 1,
|
||||
Division: {
|
||||
isActive: true,
|
||||
idVillage: idVillage,
|
||||
Group: {
|
||||
isActive: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kondisiUmum = {
|
||||
isActive: true,
|
||||
status: 1,
|
||||
idGroup: idGroup,
|
||||
}
|
||||
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
status: 1,
|
||||
@@ -397,20 +453,52 @@ export async function GET(request: Request) {
|
||||
isActive: true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kondisi = {
|
||||
isActive: true,
|
||||
status: 1,
|
||||
Division: {
|
||||
isActive: true,
|
||||
DivisionMember: {
|
||||
some: {
|
||||
idUser: user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if (roleUser == "admin" || roleUser == "cosupadmin") {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// status: 1,
|
||||
// Division: {
|
||||
// idGroup: idGroup,
|
||||
// isActive: true
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// kondisi = {
|
||||
// isActive: true,
|
||||
// status: 1,
|
||||
// Division: {
|
||||
// isActive: true,
|
||||
// DivisionMember: {
|
||||
// some: {
|
||||
// idUser: user.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// TODO:
|
||||
// const dataUmum = await prisma.discussion.findMany({
|
||||
// skip: 0,
|
||||
// take: 5,
|
||||
// where: kondisiUmum,
|
||||
// select: {
|
||||
// id: true,
|
||||
// title: true,
|
||||
// desc: true,
|
||||
// createdAt: true,
|
||||
// User: {
|
||||
// select: {
|
||||
// name: true
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// orderBy: {
|
||||
// createdAt: "desc"
|
||||
// }
|
||||
// })
|
||||
|
||||
const data = await prisma.divisionDisscussion.findMany({
|
||||
skip: 0,
|
||||
@@ -517,6 +605,8 @@ export async function GET(request: Request) {
|
||||
desc: `Tugas dengan deadline ${moment(v.dateEnd).format('DD-MM-yyyy')} telah berakhir. Silakan segera melakukan tindakan yang diperlukan.`
|
||||
}))
|
||||
|
||||
pertama.filter((item) => item.idUserTo != undefined && item.idUserTo != null && item.idUserTo != "" && item.idUserTo != user.id)
|
||||
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: pertama
|
||||
})
|
||||
@@ -576,6 +666,8 @@ export async function GET(request: Request) {
|
||||
desc: `Tugas dengan deadline ${moment(v.dateEnd).format('DD-MM-yyyy')} telah berakhir. Silakan segera melakukan tindakan yang diperlukan.`
|
||||
}))
|
||||
|
||||
kedua.filter((item) => item.idUserTo != undefined && item.idUserTo != null && item.idUserTo != "" && item.idUserTo != user.id)
|
||||
|
||||
const insertNotif2 = await prisma.notifications.createMany({
|
||||
data: kedua
|
||||
})
|
||||
|
||||
@@ -109,7 +109,10 @@ export async function PUT(request: Request, context: { params: { id: string } })
|
||||
|
||||
const cek = await prisma.position.count({
|
||||
where: {
|
||||
name: name,
|
||||
name: {
|
||||
equals: name,
|
||||
mode: "insensitive"
|
||||
},
|
||||
idGroup: idGroup,
|
||||
NOT: {
|
||||
id: id
|
||||
@@ -133,7 +136,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: "Jabatan sudah ada" },
|
||||
{ status: 400 }
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ export async function GET(request: Request) {
|
||||
id: true,
|
||||
name: true,
|
||||
isActive: true,
|
||||
idGroup: true,
|
||||
Group: {
|
||||
select: {
|
||||
name: true
|
||||
|
||||
@@ -47,4 +47,51 @@ export async function DELETE(request: Request, context: { params: { id: string }
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// EDIT PROJECT REPORT
|
||||
export async function PUT(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params
|
||||
const { report, user } = await request.json()
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
const data = await prisma.project.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
const dataCreate = await prisma.project.update({
|
||||
where: {
|
||||
id
|
||||
},
|
||||
data: {
|
||||
report: report
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate laporan kegiatan', table: 'project', data: String(id), user: userMobile.id })
|
||||
|
||||
return NextResponse.json({ success: true, message: "Laporan kegiatan berhasil diupdate" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mengupdate kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
95
src/app/api/mobile/project/[id]/link/route.ts
Normal file
95
src/app/api/mobile/project/[id]/link/route.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserById } from "@/module/auth";
|
||||
import { createLogUserMobile } from "@/module/user";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// ADD LINK PROJECT
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params
|
||||
const { link, user } = (await request.json())
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
const data = await prisma.project.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const insertLink = await prisma.projectLink.create({
|
||||
data: {
|
||||
idProject: id,
|
||||
link: link
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User menambah link kegiatan', table: 'projectLink', data: insertLink.id, user: userMobile.id })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menambahkan link kegiatan" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menambah link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DELETE LINK PROJECT
|
||||
export async function DELETE(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { idLink, user } = (await request.json())
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
const data = await prisma.projectLink.count({
|
||||
where: {
|
||||
id: idLink
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan link, data tidak ditemukan",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
const deleteLink = await prisma.projectLink.update({
|
||||
where: {
|
||||
id: idLink
|
||||
},
|
||||
data: {
|
||||
isActive: false
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'DELETE', desc: 'User menghapus link kegiatan', table: 'projectLink', data: String(idLink), user: userMobile.id })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menghapus link kegiatan" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,18 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
} else if (kategori == "link") {
|
||||
const dataLink = await prisma.projectLink.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
|
||||
allData = dataLink
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: allData, }, { status: 200 });
|
||||
@@ -150,7 +162,7 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params
|
||||
const { name, dateStart, dateEnd, user } = await request.json()
|
||||
const { name, dateStart, dateEnd, user, dataDetail } = await request.json()
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
@@ -185,6 +197,51 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
})
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: dataCreate.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
|
||||
const dataDetailCreate = await prisma.projectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// const cek progress
|
||||
const dataTask = await prisma.projectTask.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: id,
|
||||
}
|
||||
})
|
||||
|
||||
const semua = dataTask.length
|
||||
const selesai = dataTask.filter((item) => item.status == 1).length
|
||||
const prosess = Math.ceil((selesai / semua) * 100)
|
||||
let statusProject = 1
|
||||
|
||||
if (prosess == 100) {
|
||||
statusProject = 2
|
||||
} else if (prosess == 0) {
|
||||
statusProject = 0
|
||||
}
|
||||
|
||||
|
||||
const update = await prisma.project.update({
|
||||
where: {
|
||||
id: id
|
||||
},
|
||||
data: {
|
||||
status: statusProject
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data tahapan kegiatan', table: 'projectTask', data: String(dataCreate.id), user: userMobile.id })
|
||||
|
||||
|
||||
@@ -171,12 +171,14 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
const { id } = context.params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const user = searchParams.get("user");
|
||||
const kategori = searchParams.get("cat");
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
let dataFix
|
||||
const data = await prisma.projectTask.findUnique({
|
||||
where: {
|
||||
id: String(id),
|
||||
@@ -195,7 +197,29 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data: fixData }, { status: 200 });
|
||||
if (kategori == "detailTask") {
|
||||
const dataDetail = await prisma.projectTaskDetail.findMany({
|
||||
where: {
|
||||
idTask: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc"
|
||||
}
|
||||
})
|
||||
|
||||
const dataDetailFix = dataDetail.map((data: any) => ({
|
||||
...data,
|
||||
date: moment(data?.date).format('DD-MM-YYYY'),
|
||||
timeStart: data.timeStart == null ? "" : moment.utc(data.timeStart).format("HH:mm"),
|
||||
timeEnd: data.timeEnd == null ? "" : moment.utc(data.timeEnd).format("HH:mm")
|
||||
}))
|
||||
|
||||
dataFix = dataDetailFix
|
||||
} else {
|
||||
dataFix = fixData
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data: dataFix }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
@@ -207,7 +231,7 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
const { title, dateStart, dateEnd, user } = (await request.json());
|
||||
const { title, dateStart, dateEnd, user, dataDetail } = (await request.json());
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
@@ -240,6 +264,26 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
})
|
||||
|
||||
const dataDetailDelete = await prisma.projectTaskDetail.deleteMany({
|
||||
where: {
|
||||
idTask: id
|
||||
}
|
||||
})
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.projectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate tahapan kegiatan', table: 'projectTask', data: String(id), user: userMobile.id })
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
|
||||
}
|
||||
|
||||
const file = body.get("file") as File
|
||||
const fileName = file.name
|
||||
const fileName = decodeURIComponent(file.name)
|
||||
|
||||
const dataCek = await prisma.project.count({
|
||||
where: {
|
||||
|
||||
@@ -179,16 +179,33 @@ export async function POST(request: Request) {
|
||||
|
||||
if (task.length > 0) {
|
||||
const dataProject = task.map((v: any) => ({
|
||||
..._.omit(v, ["dateStart", "dateEnd", "name", "dateEndFix", "dateStartFix"]),
|
||||
..._.omit(v, ["dateStart", "dateEnd", "name", "dateEndFix", "dateStartFix", "dataDetail"]),
|
||||
idProject: data.id,
|
||||
title: v.title,
|
||||
dateStart: new Date(v.dateStartFix),
|
||||
dateEnd: new Date(v.dateEndFix),
|
||||
}))
|
||||
|
||||
let dataDetailFix = []
|
||||
for (let i = 0; i < dataProject.length; i++) {
|
||||
const insertTask = await prisma.projectTask.create({
|
||||
data: dataProject[i],
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
const dataDetail = task[i].dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: insertTask.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
dataDetailFix.push(...dataDetail)
|
||||
}
|
||||
|
||||
const insertTask = await prisma.projectTask.createMany({
|
||||
data: dataProject
|
||||
const insertDetail = await prisma.projectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
@@ -210,7 +227,7 @@ export async function POST(request: Request) {
|
||||
if (String(pair[0]).substring(0, 4) == "file") {
|
||||
const file = body.get(pair[0]) as File
|
||||
const fExt = file.name.split(".").pop()
|
||||
const fName = file.name.replace("." + fExt, "")
|
||||
const fName = decodeURIComponent(file.name.replace("." + fExt, ""))
|
||||
const upload = await funUploadFile({ file: file, dirId: DIR.project })
|
||||
if (upload.success) {
|
||||
await prisma.projectFile.create({
|
||||
@@ -267,7 +284,7 @@ export async function POST(request: Request) {
|
||||
category: 'project',
|
||||
idContent: data.id,
|
||||
title: 'Kegiatan Baru',
|
||||
desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const dataPush = memberNotif.map((v: any) => ({
|
||||
@@ -306,7 +323,7 @@ export async function POST(request: Request) {
|
||||
category: 'project',
|
||||
idContent: data.id,
|
||||
title: 'Kegiatan Baru',
|
||||
desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -353,7 +370,7 @@ export async function POST(request: Request) {
|
||||
category: 'project',
|
||||
idContent: data.id,
|
||||
title: 'Kegiatan Baru',
|
||||
desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const omitPush = atasanGroup.map((v: any) => ({
|
||||
@@ -367,18 +384,19 @@ export async function POST(request: Request) {
|
||||
tokenDup.push(...omitFCM.map((v: any) => v.tokens).flat())
|
||||
}
|
||||
|
||||
const dataNotifFilter = dataNotif.filter((item) => item.idUserTo != undefined && item.idUserTo != null && item.idUserTo != "" && item.idUserTo != userId)
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Kegiatan Baru', body: 'Terdapat kegiatan baru. Silahkan periksa detailnya.' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Kegiatan Baru', body: title } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
data: dataNotifFilter
|
||||
})
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())];
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Kegiatan Baru",
|
||||
body: "Anda memiliki kegiatan baru. Silahkan periksa detailnya.",
|
||||
body: title,
|
||||
data: { id: data.id, category: "project", content: data.id }
|
||||
})
|
||||
|
||||
|
||||
@@ -46,4 +46,51 @@ export async function DELETE(request: Request, context: { params: { id: string }
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// EDIT TASK REPORT
|
||||
export async function PUT(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params
|
||||
const { report, user } = await request.json()
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
|
||||
const data = await prisma.divisionProject.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
const dataCreate = await prisma.divisionProject.update({
|
||||
where: {
|
||||
id
|
||||
},
|
||||
data: {
|
||||
report: report
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate laporan tugas divisi', table: 'divisionProject', data: String(id), user: userMobile.id })
|
||||
|
||||
return NextResponse.json({ success: true, message: "Laporan tugas divisi berhasil diupdate" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mengupdate laporan tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
98
src/app/api/mobile/task/[id]/link/route.ts
Normal file
98
src/app/api/mobile/task/[id]/link/route.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserById } from "@/module/auth";
|
||||
import { createLogUserMobile } from "@/module/user";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// ADD LINK TASK DIVISI
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
const { link, idDivision, user } = (await request.json());
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
const data = await prisma.divisionProject.count({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Tambah link tugas gagal, data tugas tidak ditemukan",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const insertlink = await prisma.divisionProjectLink.create({
|
||||
data: {
|
||||
idProject: id,
|
||||
link,
|
||||
idDivision,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'CREATE', desc: 'User menambahkan link tugas divisi', table: 'divisionProjectLink', data: insertlink.id, user: userMobile.id })
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil menambahkan link tugas", }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menambah link tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DELETE LINK TASK DIVISI
|
||||
export async function DELETE(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { idLink, user } = (await request.json())
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
|
||||
}
|
||||
|
||||
const data = await prisma.divisionProjectLink.count({
|
||||
where: {
|
||||
id: idLink
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan link, data tidak ditemukan",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
const deleteLink = await prisma.divisionProjectLink.update({
|
||||
where: {
|
||||
id: idLink
|
||||
},
|
||||
data: {
|
||||
isActive: false
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'DELETE', desc: 'User menghapus link tugas divisi', table: 'divisionProjectLink', data: String(idLink), user: userMobile.id })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menghapus link tugas divisi" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus link tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,18 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
} else if (kategori == "link") {
|
||||
const dataLink = await prisma.divisionProjectLink.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
|
||||
allData = dataLink
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan tugas divisi", data: allData }, { status: 200 });
|
||||
@@ -167,7 +179,7 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
const { title, dateStart, dateEnd, idDivision, user } = (await request.json());
|
||||
const { title, dateStart, dateEnd, idDivision, user, dataDetail } = (await request.json());
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
@@ -203,6 +215,20 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
});
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: create.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// const cek progress
|
||||
const dataTask = await prisma.divisionProjectTask.findMany({
|
||||
where: {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { prisma } from "@/module/_global";
|
||||
import { funGetUserById } from "@/module/auth";
|
||||
import { createLogUserMobile } from "@/module/user";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
@@ -166,6 +167,7 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
const { id } = context.params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const user = searchParams.get("user");
|
||||
const kategori = searchParams.get("cat");
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
@@ -183,7 +185,30 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan detail tugas, data tidak ditemukan" }, { status: 200 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data }, { status: 200 });
|
||||
let dataFix
|
||||
if (kategori == "detailTask") {
|
||||
const dataDetail = await prisma.divisionProjectTaskDetail.findMany({
|
||||
where: {
|
||||
idTask: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc"
|
||||
}
|
||||
})
|
||||
|
||||
const dataDetailFix = dataDetail.map((data: any) => ({
|
||||
...data,
|
||||
date: moment(data?.date).format('DD-MM-YYYY'),
|
||||
timeStart: data.timeStart == null ? "" : moment.utc(data.timeStart).format("HH:mm"),
|
||||
timeEnd: data.timeEnd == null ? "" : moment.utc(data.timeEnd).format("HH:mm")
|
||||
}))
|
||||
|
||||
dataFix = dataDetailFix
|
||||
} else {
|
||||
dataFix = data
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data: dataFix }, { status: 200 });
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
@@ -198,7 +223,7 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
const { title, dateStart, dateEnd, user } = (await request.json());
|
||||
const { title, dateStart, dateEnd, user, dataDetail } = (await request.json());
|
||||
|
||||
const userMobile = await funGetUserById({ id: String(user) })
|
||||
if (userMobile.id == "null" || userMobile.id == undefined || userMobile.id == "") {
|
||||
@@ -232,6 +257,26 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
},
|
||||
});
|
||||
|
||||
const dataDetailDelete = await prisma.divisionProjectTaskDetail.deleteMany({
|
||||
where: {
|
||||
idTask: id
|
||||
}
|
||||
})
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// create log user
|
||||
const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengupdate data detail task divisi', table: 'divisionProjectTask', data: id, user: userMobile.id })
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
|
||||
}
|
||||
|
||||
const file = body.get("file") as File
|
||||
const fileName = file.name
|
||||
const fileName = decodeURIComponent(file.name)
|
||||
|
||||
const dataCek = await prisma.divisionProject.count({
|
||||
where: {
|
||||
|
||||
@@ -142,7 +142,7 @@ export async function POST(request: Request) {
|
||||
|
||||
if (task.length > 0) {
|
||||
const dataTask = task.map((v: any) => ({
|
||||
..._.omit(v, ["dateStart", "dateEnd", "title", "dateStartFix", "dateEndFix"]),
|
||||
..._.omit(v, ["dateStart", "dateEnd", "title", "dateStartFix", "dateEndFix", "dataDetail"]),
|
||||
idDivision: idDivision,
|
||||
idProject: data.id,
|
||||
title: v.title,
|
||||
@@ -150,9 +150,26 @@ export async function POST(request: Request) {
|
||||
dateEnd: new Date(v.dateEndFix),
|
||||
}))
|
||||
|
||||
let dataDetailFix = []
|
||||
for (let i = 0; i < dataTask.length; i++) {
|
||||
const insertTask = await prisma.divisionProjectTask.create({
|
||||
data: dataTask[i],
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
const dataDetail = task[i].dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: insertTask.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
dataDetailFix.push(...dataDetail)
|
||||
}
|
||||
|
||||
const insertTask = await prisma.divisionProjectTask.createMany({
|
||||
data: dataTask
|
||||
const insertDetail = await prisma.divisionProjectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
@@ -250,8 +267,8 @@ export async function POST(request: Request) {
|
||||
idUserFrom: String(userMobile.id),
|
||||
category: 'division/' + idDivision + '/task',
|
||||
idContent: data.id,
|
||||
title: 'Tugas Baru',
|
||||
desc: 'Terdapat tugas baru. Silahkan periksa detailnya.'
|
||||
title: 'Tugas Divisi Baru',
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const dataPush = memberDivision.map((v: any) => ({
|
||||
@@ -289,8 +306,8 @@ export async function POST(request: Request) {
|
||||
idUserFrom: userId,
|
||||
category: 'division/' + idDivision + '/task',
|
||||
idContent: data.id,
|
||||
title: 'Tugas Baru',
|
||||
desc: 'Terdapat tugas baru. Silahkan periksa detailnya.'
|
||||
title: 'Tugas Divisi Baru',
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -328,8 +345,8 @@ export async function POST(request: Request) {
|
||||
idUserFrom: userId,
|
||||
category: 'division/' + idDivision + '/task',
|
||||
idContent: data.id,
|
||||
title: 'Tugas Baru',
|
||||
desc: 'Terdapat tugas baru. Silahkan periksa detailnya.'
|
||||
title: 'Tugas Divisi Baru',
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -338,19 +355,20 @@ export async function POST(request: Request) {
|
||||
})
|
||||
}
|
||||
|
||||
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat tugas baru. Silahkan periksa detailnya.', title: 'Tugas Baru' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: title, title: 'Tugas Divisi Baru' } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
data: dataNotifFilter
|
||||
})
|
||||
|
||||
const tokenUnique = [...new Set(tokenDup.flat())];
|
||||
const tokenUnique = [...new Set(tokenDup.flat())].filter((v: any) => v != undefined && v != null && v != "");
|
||||
await sendFCMNotificationMany({
|
||||
token: tokenUnique,
|
||||
title: "Tugas Baru",
|
||||
body: "Anda memiliki tugas baru. Silahkan periksa detailnya.",
|
||||
data: { id: data.id, category:'division/' + idDivision + '/task', content: data.id }
|
||||
title: "Tugas Divisi Baru",
|
||||
body: title,
|
||||
data: { id: data.id, category: 'division/' + idDivision + '/task', content: data.id }
|
||||
})
|
||||
|
||||
// create log user
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DIR, funUploadFile, prisma } from "@/module/_global";
|
||||
import { funGetUserById } from "@/module/auth";
|
||||
import { createLogUser, createLogUserMobile } from "@/module/user";
|
||||
import { createLogUserMobile } from "@/module/user";
|
||||
import _ from "lodash";
|
||||
import { NextResponse } from "next/server";
|
||||
import sharp from "sharp";
|
||||
@@ -39,7 +39,7 @@ export async function GET(request: Request) {
|
||||
}
|
||||
})
|
||||
|
||||
if (page != "undefined" && page != "null" && page != "" && page!=undefined && page!=null) {
|
||||
if (page != "undefined" && page != "null" && page != "" && page != undefined && page != null) {
|
||||
const users = await prisma.user.findMany({
|
||||
skip: dataSkip,
|
||||
take: 10,
|
||||
@@ -238,7 +238,17 @@ export async function POST(request: Request) {
|
||||
|
||||
return Response.json({ success: true, message: 'Sukses membuat user' }, { status: 200 });
|
||||
} else {
|
||||
return Response.json({ success: false, message: "User sudah ada" }, { status: 200 });
|
||||
if (cekNIK > 0) {
|
||||
return Response.json({ success: false, message: "NIK sudah terdaftar" }, { status: 200 });
|
||||
}
|
||||
|
||||
if (cekEmail > 0) {
|
||||
return Response.json({ success: false, message: "Email sudah terdaftar" }, { status: 200 });
|
||||
}
|
||||
|
||||
if (cekPhone > 0) {
|
||||
return Response.json({ success: false, message: "Nomor telepon sudah terdaftar" }, { status: 200 });
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
@@ -45,4 +45,50 @@ export async function DELETE(request: Request, context: { params: { id: string }
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// EDIT PROJECT REPORT
|
||||
export async function PUT(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const user = await funGetUserByCookies()
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = context.params
|
||||
const { report } = await request.json()
|
||||
|
||||
const data = await prisma.project.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const dataCreate = await prisma.project.update({
|
||||
where: {
|
||||
id
|
||||
},
|
||||
data: {
|
||||
report: report
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate laporan kegiatan', table: 'project', data: String(id) })
|
||||
|
||||
return NextResponse.json({ success: true, message: "Laporan kegiatan berhasil diupdate" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mengupdate kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
93
src/app/api/project/[id]/link/route.ts
Normal file
93
src/app/api/project/[id]/link/route.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserByCookies } from "@/module/auth";
|
||||
import { createLogUser } from "@/module/user";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// ADD LINK PROJECT
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const user = await funGetUserByCookies()
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = context.params
|
||||
const { link } = (await request.json())
|
||||
|
||||
const data = await prisma.project.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const insertLink = await prisma.projectLink.create({
|
||||
data: {
|
||||
idProject: id,
|
||||
link: link
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'CREATE', desc: 'User menambah link kegiatan', table: 'projectLink', data: insertLink.id })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menambahkan link kegiatan" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menambah link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DELETE LINK PROJECT
|
||||
export async function DELETE(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const user = await funGetUserByCookies()
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { idLink } = (await request.json())
|
||||
|
||||
const data = await prisma.projectLink.count({
|
||||
where: {
|
||||
id: idLink
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan link, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const deleteLink = await prisma.projectLink.update({
|
||||
where: {
|
||||
id: idLink
|
||||
},
|
||||
data: {
|
||||
isActive: false
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus link kegiatan', table: 'projectLink', data: String(idLink) })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menghapus link kegiatan" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus link kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -133,6 +133,17 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
} else if (kategori == "link") {
|
||||
const dataLink = await prisma.projectLink.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
allData = dataLink
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: allData, }, { status: 200 });
|
||||
@@ -152,7 +163,7 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
|
||||
const { id } = context.params
|
||||
const { name, dateStart, dateEnd, } = await request.json()
|
||||
const { name, dateStart, dateEnd, dataDetail } = await request.json()
|
||||
|
||||
const data = await prisma.project.count({
|
||||
where: {
|
||||
@@ -181,6 +192,50 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
})
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: dataCreate.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.projectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// const cek progress
|
||||
const dataTask = await prisma.projectTask.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: id,
|
||||
}
|
||||
})
|
||||
|
||||
const semua = dataTask.length
|
||||
const selesai = dataTask.filter((item) => item.status == 1).length
|
||||
const prosess = Math.ceil((selesai / semua) * 100)
|
||||
let statusProject = 1
|
||||
|
||||
if (prosess == 100) {
|
||||
statusProject = 2
|
||||
} else if (prosess == 0) {
|
||||
statusProject = 0
|
||||
}
|
||||
|
||||
|
||||
const update = await prisma.project.update({
|
||||
where: {
|
||||
id: id
|
||||
},
|
||||
data: {
|
||||
status: statusProject
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data tahapan kegiatan', table: 'projectTask', data: String(dataCreate.id) })
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserByCookies } from "@/module/auth";
|
||||
import { createLogUser } from "@/module/user";
|
||||
import moment from "moment";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
@@ -171,7 +172,11 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const kategori = searchParams.get("cat");
|
||||
const { id } = context.params;
|
||||
|
||||
let dataFix
|
||||
const data = await prisma.projectTask.findUnique({
|
||||
where: {
|
||||
id: String(id),
|
||||
@@ -188,7 +193,28 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data }, { status: 200 });
|
||||
if (kategori == "detailTask") {
|
||||
const dataDetail = await prisma.projectTaskDetail.findMany({
|
||||
where: {
|
||||
idTask: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc"
|
||||
}
|
||||
})
|
||||
|
||||
const dataDetailFix = dataDetail.map((data: any) => ({
|
||||
...data,
|
||||
timeStart: moment.utc(data.timeStart).format("HH:mm"),
|
||||
timeEnd: moment.utc(data.timeEnd).format("HH:mm")
|
||||
}))
|
||||
|
||||
dataFix = dataDetailFix
|
||||
} else {
|
||||
dataFix = data
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Detail kegiatan berhasil ditemukan", data: dataFix }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
@@ -205,17 +231,17 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
|
||||
const { id } = context.params;
|
||||
const { title, dateStart, dateEnd } = (await request.json());
|
||||
const { title, dateStart, dateEnd, dataDetail } = (await request.json());
|
||||
|
||||
|
||||
|
||||
const dataTask = await prisma.projectTask.count({
|
||||
const dataTaskLama = await prisma.projectTask.findUnique({
|
||||
where: {
|
||||
id
|
||||
}
|
||||
})
|
||||
|
||||
if (dataTask == 0) {
|
||||
if (dataTaskLama?.title == undefined) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
@@ -235,6 +261,26 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
})
|
||||
|
||||
const dataDetailDelete = await prisma.projectTaskDetail.deleteMany({
|
||||
where: {
|
||||
idTask: id
|
||||
}
|
||||
})
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.projectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate tahapan kegiatan', table: 'projectTask', data: String(id) })
|
||||
|
||||
|
||||
@@ -169,15 +169,34 @@ export async function POST(request: Request) {
|
||||
|
||||
if (task.length > 0) {
|
||||
const dataProject = task.map((v: any) => ({
|
||||
..._.omit(v, ["dateStart", "dateEnd", "name"]),
|
||||
..._.omit(v, ["dateStart", "dateEnd", "name", "dataDetail"]),
|
||||
idProject: data.id,
|
||||
title: v.title,
|
||||
dateStart: new Date(v.dateStart),
|
||||
dateEnd: new Date(v.dateEnd),
|
||||
}))
|
||||
|
||||
const insertTask = await prisma.projectTask.createMany({
|
||||
data: dataProject
|
||||
let dataDetailFix = []
|
||||
|
||||
for (let i = 0; i < dataProject.length; i++) {
|
||||
const insertTask = await prisma.projectTask.create({
|
||||
data: dataProject[i],
|
||||
select:{
|
||||
id: true
|
||||
}
|
||||
})
|
||||
const dataDetail = task[i].dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: insertTask.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
dataDetailFix.push(...dataDetail)
|
||||
}
|
||||
|
||||
const insertDetail = await prisma.projectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
@@ -243,7 +262,7 @@ export async function POST(request: Request) {
|
||||
category: 'project',
|
||||
idContent: data.id,
|
||||
title: 'Kegiatan Baru',
|
||||
desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const dataPush = memberNotif.map((v: any) => ({
|
||||
@@ -275,7 +294,7 @@ export async function POST(request: Request) {
|
||||
category: 'project',
|
||||
idContent: data.id,
|
||||
title: 'Kegiatan Baru',
|
||||
desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -311,7 +330,7 @@ export async function POST(request: Request) {
|
||||
category: 'project',
|
||||
idContent: data.id,
|
||||
title: 'Kegiatan Baru',
|
||||
desc: 'Terdapat kegiatan baru. Silahkan periksa detailnya.'
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const omitPush = atasanGroup.map((v: any) => ({
|
||||
@@ -327,7 +346,7 @@ export async function POST(request: Request) {
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Kegiatan Baru', body: 'Terdapat kegiatan baru. Silahkan periksa detailnya.' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Kegiatan Baru', body: title } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
})
|
||||
|
||||
@@ -45,4 +45,52 @@ export async function DELETE(request: Request, context: { params: { id: string }
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// EDIT TASK REPORT
|
||||
export async function PUT(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const user = await funGetUserByCookies()
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = context.params
|
||||
const { report } = await request.json()
|
||||
|
||||
|
||||
const data = await prisma.divisionProject.count({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const dataCreate = await prisma.divisionProject.update({
|
||||
where: {
|
||||
id
|
||||
},
|
||||
data: {
|
||||
report: report
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate laporan tugas divisi', table: 'divisionProject', data: String(id) })
|
||||
|
||||
return NextResponse.json({ success: true, message: "Laporan tugas divisi berhasil diupdate" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal mengupdate laporan tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
98
src/app/api/task/[id]/link/route.ts
Normal file
98
src/app/api/task/[id]/link/route.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import { funGetUserByCookies } from "@/module/auth";
|
||||
import { createLogUser } from "@/module/user";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// ADD LINK TASK DIVISI
|
||||
export async function POST(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const user = await funGetUserByCookies()
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id } = context.params;
|
||||
const { link, idDivision } = (await request.json());
|
||||
|
||||
const data = await prisma.divisionProject.count({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Tambah link tugas gagal, data tugas tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const insertlink = await prisma.divisionProjectLink.create({
|
||||
data: {
|
||||
idProject: id,
|
||||
link,
|
||||
idDivision,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'CREATE', desc: 'User menambahkan link tugas divisi', table: 'divisionProjectLink', data: insertlink.id })
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil menambahkan link tugas", }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menambah link tugas, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DELETE LINK TASK DIVISI
|
||||
export async function DELETE(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const user = await funGetUserByCookies()
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { idLink } = (await request.json())
|
||||
|
||||
const data = await prisma.divisionProjectLink.count({
|
||||
where: {
|
||||
id: idLink
|
||||
}
|
||||
})
|
||||
|
||||
if (data == 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false, message: "Gagal mendapatkan link, data tidak ditemukan",
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const deleteLink = await prisma.divisionProjectLink.update({
|
||||
where: {
|
||||
id: idLink
|
||||
},
|
||||
data: {
|
||||
isActive: false
|
||||
}
|
||||
})
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'DELETE', desc: 'User menghapus link tugas divisi', table: 'divisionProjectLink', data: String(idLink) })
|
||||
return NextResponse.json({ success: true, message: "Berhasil menghapus link tugas divisi" }, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, message: "Gagal menghapus link tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -150,6 +150,18 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
}))
|
||||
|
||||
allData = fix
|
||||
} else if (kategori == "link") {
|
||||
const dataLink = await prisma.divisionProjectLink.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
idProject: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc'
|
||||
}
|
||||
})
|
||||
|
||||
allData = dataLink
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan tugas divisi", data: allData }, { status: 200 });
|
||||
@@ -171,7 +183,8 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
|
||||
const { id } = context.params;
|
||||
const { title, dateStart, dateEnd, idDivision } = (await request.json());
|
||||
const { title, dateStart, dateEnd, idDivision, dataDetail } = (await request.json());
|
||||
|
||||
const data = await prisma.divisionProject.count({
|
||||
where: {
|
||||
id: id,
|
||||
@@ -201,6 +214,20 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
});
|
||||
|
||||
if(dataDetail.length>0){
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: create.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// const cek progress
|
||||
const dataTask = await prisma.divisionProjectTask.findMany({
|
||||
where: {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { prisma } from "@/module/_global";
|
||||
import { funGetUserByCookies } from "@/module/auth";
|
||||
import { createLogUser } from "@/module/user";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
@@ -155,12 +156,15 @@ export async function PUT(request: Request, context: { params: { id: string } })
|
||||
export async function GET(request: Request, context: { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = context.params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const kategori = searchParams.get("cat");
|
||||
const user = await funGetUserByCookies()
|
||||
|
||||
if (user.id == undefined) {
|
||||
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
|
||||
}
|
||||
|
||||
let dataFix
|
||||
const data = await prisma.divisionProjectTask.findUnique({
|
||||
where: {
|
||||
id: String(id),
|
||||
@@ -172,7 +176,28 @@ export async function GET(request: Request, context: { params: { id: string } })
|
||||
return NextResponse.json({ success: false, message: "Gagal mendapatkan detail tugas, data tidak ditemukan", }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data }, { status: 200 });
|
||||
if (kategori == "detailTask") {
|
||||
const dataDetail = await prisma.divisionProjectTaskDetail.findMany({
|
||||
where: {
|
||||
idTask: String(id)
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc"
|
||||
}
|
||||
})
|
||||
|
||||
const dataDetailFix = dataDetail.map((data: any) => ({
|
||||
...data,
|
||||
timeStart: moment.utc(data.timeStart).format("HH:mm"),
|
||||
timeEnd: moment.utc(data.timeEnd).format("HH:mm")
|
||||
}))
|
||||
|
||||
dataFix = dataDetailFix
|
||||
} else {
|
||||
dataFix = data
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "Berhasil mendapatkan detail tugas divisi", data: dataFix }, { status: 200 });
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
@@ -192,7 +217,7 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
}
|
||||
|
||||
const { id } = context.params;
|
||||
const { title, dateStart, dateEnd } = (await request.json());
|
||||
const { title, dateStart, dateEnd, dataDetail } = (await request.json());
|
||||
const data = await prisma.divisionProjectTask.count({
|
||||
where: {
|
||||
id: id,
|
||||
@@ -220,6 +245,26 @@ export async function POST(request: Request, context: { params: { id: string } }
|
||||
},
|
||||
});
|
||||
|
||||
const dataDetailDelete = await prisma.divisionProjectTaskDetail.deleteMany({
|
||||
where: {
|
||||
idTask: id
|
||||
}
|
||||
})
|
||||
|
||||
if (dataDetail.length > 0) {
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
|
||||
const dataDetailCreate = await prisma.divisionProjectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
// create log user
|
||||
const log = await createLogUser({ act: 'UPDATE', desc: 'User mengupdate data detail task divisi', table: 'divisionProjectTask', data: id })
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ export async function POST(request: Request) {
|
||||
|
||||
if (task.length > 0) {
|
||||
const dataTask = task.map((v: any) => ({
|
||||
..._.omit(v, ["dateStart", "dateEnd", "title"]),
|
||||
..._.omit(v, ["dateStart", "dateEnd", "title", "dataDetail"]),
|
||||
idDivision: idDivision,
|
||||
idProject: data.id,
|
||||
title: v.title,
|
||||
@@ -148,8 +148,26 @@ export async function POST(request: Request) {
|
||||
dateEnd: new Date(v.dateEnd),
|
||||
}))
|
||||
|
||||
const insertTask = await prisma.divisionProjectTask.createMany({
|
||||
data: dataTask
|
||||
let dataDetailFix = []
|
||||
for (let i = 0; i < dataTask.length; i++) {
|
||||
const insertTask = await prisma.divisionProjectTask.create({
|
||||
data: dataTask[i],
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
const dataDetail = task[i].dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
idTask: insertTask.id,
|
||||
date: new Date(v.date),
|
||||
timeStart: v.timeStart == null ? null : new Date(new Date('1970-01-01 ' + v.timeStart).getTime() - (new Date('1970-01-01 ' + v.timeStart).getTimezoneOffset() * 60000)).toISOString(),
|
||||
timeEnd: v.timeEnd == null ? null : new Date(new Date('1970-01-01 ' + v.timeEnd).getTime() - (new Date('1970-01-01 ' + v.timeEnd).getTimezoneOffset() * 60000)).toISOString(),
|
||||
}))
|
||||
dataDetailFix.push(...dataDetail)
|
||||
}
|
||||
|
||||
const insertDetail = await prisma.divisionProjectTaskDetail.createMany({
|
||||
data: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
@@ -235,8 +253,8 @@ export async function POST(request: Request) {
|
||||
idUserFrom: String(user.id),
|
||||
category: 'division/' + idDivision + '/task',
|
||||
idContent: data.id,
|
||||
title: 'Tugas Baru',
|
||||
desc: 'Terdapat tugas baru. Silahkan periksa detailnya.'
|
||||
title: 'Tugas Divisi Baru',
|
||||
desc: title
|
||||
}))
|
||||
|
||||
const dataPush = memberDivision.map((v: any) => ({
|
||||
@@ -267,8 +285,8 @@ export async function POST(request: Request) {
|
||||
idUserFrom: userId,
|
||||
category: 'division/' + idDivision + '/task',
|
||||
idContent: data.id,
|
||||
title: 'Tugas Baru',
|
||||
desc: 'Terdapat tugas baru. Silahkan periksa detailnya.'
|
||||
title: 'Tugas Divisi Baru',
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -299,8 +317,8 @@ export async function POST(request: Request) {
|
||||
idUserFrom: userId,
|
||||
category: 'division/' + idDivision + '/task',
|
||||
idContent: data.id,
|
||||
title: 'Tugas Baru',
|
||||
desc: 'Terdapat tugas baru. Silahkan periksa detailnya.'
|
||||
title: 'Tugas Divisi Baru',
|
||||
desc: title
|
||||
})
|
||||
|
||||
dataPush.push({
|
||||
@@ -311,13 +329,12 @@ export async function POST(request: Request) {
|
||||
|
||||
const pushNotif = dataPush.filter((item) => item.subscription != undefined)
|
||||
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat tugas baru. Silahkan periksa detailnya.', title: 'Tugas Baru' } })
|
||||
const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: title, title: 'Tugas Divisi Baru' } })
|
||||
const insertNotif = await prisma.notifications.createMany({
|
||||
data: dataNotif
|
||||
})
|
||||
|
||||
|
||||
// create log user
|
||||
// create log userc
|
||||
const log = await createLogUser({ act: 'CREATE', desc: 'User membuat tugas divisi baru', table: 'divisionProject', data: data.id })
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
return NextResponse.json({ success: true, version: "1.5.7", tahap: "beta", update: "-fix mobile api" }, { status: 200 });
|
||||
return NextResponse.json({ success: true, version: "2.0.4", tahap: "beta", update: "-api mobile; -login tanpa otp (mobile app); -tambah laporan pada project dan tugas divisi; -tambah upload link pada project dan tugas divisi; -tambah detail tanggal dan jam pada project dan tugas divisi; -api jenna ai; -privacy policy" }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, version: "Gagal mendapatkan version, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
|
||||
259
src/app/util/privacy-policy/page.tsx
Normal file
259
src/app/util/privacy-policy/page.tsx
Normal file
@@ -0,0 +1,259 @@
|
||||
"use client";
|
||||
|
||||
export default function PrivacyPolicyPage() {
|
||||
return (
|
||||
<div dangerouslySetInnerHTML={{ __html: htmlContent }} />
|
||||
);
|
||||
}
|
||||
|
||||
const htmlContent = `
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Privacy Policy — Bali Interaktif Perkasa</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--fg: #111111;
|
||||
--muted: #555555;
|
||||
--accent: #0a7cff;
|
||||
--card: #f7f7f8;
|
||||
--border: #e5e7eb;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
|
||||
color: var(--fg);
|
||||
background: var(--bg);
|
||||
line-height: 1.6;
|
||||
}
|
||||
header {
|
||||
padding: 2.5rem 1rem 1rem;
|
||||
background: linear-gradient(180deg, #eef4ff, #fff);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.container {
|
||||
max-width: 840px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem 3rem;
|
||||
}
|
||||
h1 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: clamp(1.6rem, 3vw, 2.2rem);
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.updated {
|
||||
color: var(--muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
nav.toc {
|
||||
background: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 1rem 1.25rem;
|
||||
margin: 1.25rem 0 2rem;
|
||||
}
|
||||
nav.toc h2 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
nav.toc ol {
|
||||
margin: 0.25rem 0 0.5rem 1.25rem;
|
||||
}
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
section { margin: 2rem 0; }
|
||||
h2 {
|
||||
font-size: 1.35rem;
|
||||
margin: 0 0 0.5rem;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
h3 { font-size: 1.05rem; margin: 1rem 0 0.25rem; }
|
||||
.summary {
|
||||
background: #fffef5;
|
||||
border: 1px solid #f1e8c6;
|
||||
border-radius: 12px;
|
||||
padding: 1rem 1.25rem;
|
||||
}
|
||||
ul, ol { padding-left: 1.25rem; }
|
||||
address { font-style: normal; white-space: pre-line; }
|
||||
footer {
|
||||
margin-top: 2.5rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--border);
|
||||
color: var(--muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
code { background: #f1f5f9; padding: 0.1rem 0.3rem; border-radius: 6px; }
|
||||
.lead { font-size: 1.05rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="container">
|
||||
<h1>Privacy Policy</h1>
|
||||
<div class="updated">Last updated September 01, 2025</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<p class="lead">
|
||||
This Privacy Notice for <strong>Bali Interaktif Perkasa</strong> ("we," "us," or "our") describes how and why we might access, collect, store, use, and/or share ("process") your personal information when you use our services ("Services"), including when you:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Download and use our mobile application (<em>Darmasaba mobile</em>), or any other application of ours that links to this Privacy Notice.</li>
|
||||
<li>Use Administration. This mobile application is specifically designed to help village officials manage data and monitor the progress of internal activities. It offers features such as data management by division, general activity monitoring, discussion forums, official announcements, and document folder management.</li>
|
||||
<li>Engage with us in other related ways, including any sales, marketing, or events.</li>
|
||||
</ul>
|
||||
<p>Questions or concerns? Reading this Privacy Notice will help you understand your privacy rights and choices. We are responsible for making decisions about how your personal information is processed. If you do not agree with our policies and practices, please do not use our Services. If you still have any questions or concerns, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
|
||||
<section class="summary">
|
||||
<h2>Summary of Key Points</h2>
|
||||
<p>This summary provides key points from our Privacy Notice, but you can find out more details about any of these topics by using the table of contents below.</p>
|
||||
<ul>
|
||||
<li><strong>What personal information do we process?</strong> We may process personal information depending on how you interact with us and the Services, the choices you make, and the products and features you use.</li>
|
||||
<li><strong>Do we process any sensitive personal information?</strong> We do not process sensitive personal information.</li>
|
||||
<li><strong>Do we collect any information from third parties?</strong> We do not collect any information from third parties.</li>
|
||||
<li><strong>How do we process your information?</strong> To provide, improve, and administer our Services; communicate with you; for security and fraud prevention; and to comply with law. We may also process your information for other purposes with your consent.</li>
|
||||
<li><strong>In what situations and with which parties do we share personal information?</strong> We may share information in specific situations and with specific third parties.</li>
|
||||
<li><strong>How do we keep your information safe?</strong> We have organizational and technical measures to protect your personal information; however, no method is 100% secure.</li>
|
||||
<li><strong>What are your rights?</strong> Depending on your location, you may have certain rights regarding your personal information.</li>
|
||||
<li><strong>How do you exercise your rights?</strong> The easiest way is by emailing <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</li>
|
||||
</ul>
|
||||
<p>Want to learn more about what we do with information we collect? Review the Privacy Notice in full below.</p>
|
||||
</section>
|
||||
|
||||
<nav class="toc" aria-label="Table of contents">
|
||||
<h2>Table of Contents</h2>
|
||||
<ol>
|
||||
<li><a href="#collect">1. WHAT INFORMATION DO WE COLLECT?</a></li>
|
||||
<li><a href="#process">2. HOW DO WE PROCESS YOUR INFORMATION?</a></li>
|
||||
<li><a href="#share">3. WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION?</a></li>
|
||||
<li><a href="#retention">4. HOW LONG DO WE KEEP YOUR INFORMATION?</a></li>
|
||||
<li><a href="#security">5. HOW DO WE KEEP YOUR INFORMATION SAFE?</a></li>
|
||||
<li><a href="#minors">6. DO WE COLLECT INFORMATION FROM MINORS?</a></li>
|
||||
<li><a href="#rights">7. WHAT ARE YOUR PRIVACY RIGHTS?</a></li>
|
||||
<li><a href="#dnt">8. CONTROLS FOR DO-NOT-TRACK FEATURES</a></li>
|
||||
<li><a href="#updates">9. DO WE MAKE UPDATES TO THIS NOTICE?</a></li>
|
||||
<li><a href="#contact">10. HOW CAN YOU CONTACT US ABOUT THIS NOTICE?</a></li>
|
||||
<li><a href="#review">11. HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU?</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<section id="collect">
|
||||
<h2>1. WHAT INFORMATION DO WE COLLECT?</h2>
|
||||
<h3>Personal information you disclose to us</h3>
|
||||
<p><em>In Short:</em> We collect personal information that you provide to us.</p>
|
||||
<p>We collect personal information that you voluntarily provide to us when you express an interest in obtaining information about us or our products and Services, when you participate in activities on the Services, or otherwise when you contact us.</p>
|
||||
<h3>Personal Information Provided by You</h3>
|
||||
<p>The personal information we collect depends on the context of your interactions with us and the Services, the choices you make, and the products and features you use. This may include:</p>
|
||||
<ul>
|
||||
<li>names</li>
|
||||
<li>phone numbers</li>
|
||||
<li>email addresses</li>
|
||||
</ul>
|
||||
<h3>Sensitive Information</h3>
|
||||
<p>We do not process sensitive information.</p>
|
||||
<h3>Application Data</h3>
|
||||
<p>If you use our application(s), we may also collect the following information if you choose to provide us with access or permission:</p>
|
||||
<ul>
|
||||
<li><strong>Mobile Device Access.</strong> We may request access or permission to certain features from your mobile device, including your mobile device's camera, and other features. You may change access or permissions in your device's settings.</li>
|
||||
<li><strong>Push Notifications.</strong> We may request to send you push notifications regarding your account or certain features of the application(s). You may opt out in your device's settings.</li>
|
||||
</ul>
|
||||
<p>This information is primarily needed to maintain the security and operation of our application(s), for troubleshooting, and for internal analytics and reporting purposes.</p>
|
||||
<p>All personal information that you provide to us must be true, complete, and accurate, and you must notify us of any changes to such personal information.</p>
|
||||
</section>
|
||||
|
||||
<section id="process">
|
||||
<h2>2. HOW DO WE PROCESS YOUR INFORMATION?</h2>
|
||||
<p><em>In Short:</em> We process your information to provide, improve, and administer our Services, communicate with you, for security and fraud prevention, and to comply with law. We may also process your information for other purposes with your consent.</p>
|
||||
<p>We process your personal information for a variety of reasons, depending on how you interact with our Services, including:</p>
|
||||
<ul>
|
||||
<li><strong>To deliver and facilitate delivery of services to the user.</strong> We may process your information to provide you with the requested service.</li>
|
||||
<li><strong>To enable user-to-user communications.</strong> We may process your information if you choose to use offerings that allow communication with another user.</li>
|
||||
<li><strong>To evaluate and improve our Services, products, marketing, and your experience.</strong> We may process your information to identify usage trends, determine the effectiveness of our promotional campaigns, and to evaluate and improve our Services, products, marketing, and your experience.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="share">
|
||||
<h2>3. WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION?</h2>
|
||||
<p><em>In Short:</em> We may share information in specific situations described in this section and/or with the following third parties.</p>
|
||||
<p><strong>Vendors, Consultants, and Other Third-Party Service Providers.</strong> We may share your data with third-party vendors, service providers, contractors, or agents ("third parties") who perform services for us or on our behalf and require access to such information to do that work.</p>
|
||||
<p>The third parties we may share personal information with include:</p>
|
||||
<ul>
|
||||
<li><strong>Functionality and Infrastructure Optimization:</strong> Firebase Realtime Database and Cloud Functions for Firebase</li>
|
||||
<li><strong>Functionality & Infrastructure Optimization:</strong> Expo / EAS Services</li>
|
||||
</ul>
|
||||
<p>We may also need to share your personal information in the following situations:</p>
|
||||
<ul>
|
||||
<li><strong>Business Transfers.</strong> We may share or transfer your information in connection with, or during negotiations of, any merger, sale of company assets, financing, or acquisition of all or a portion of our business to another company.</li>
|
||||
<li><strong>Other Users.</strong> When you share personal information (for example, by posting comments or other content to the Services) or interact with public areas of the Services, such information may be viewed by all users and may be publicly available outside the Services in perpetuity. Other users may view descriptions of your activity, communicate with you, and view your profile.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="retention">
|
||||
<h2>4. HOW LONG DO WE KEEP YOUR INFORMATION?</h2>
|
||||
<p><em>In Short:</em> We keep your information for as long as necessary to fulfill the purposes outlined in this Privacy Notice unless otherwise required by law.</p>
|
||||
<p>We will only keep your personal information as long as necessary for the purposes set out in this Privacy Notice, unless a longer retention period is required or permitted by law (such as tax, accounting, or other legal requirements).</p>
|
||||
<p>When we have no ongoing legitimate business need to process your personal information, we will delete or anonymize such information. If deletion is not possible (for example, if your personal information is stored in backup archives), we will securely store your personal information and isolate it from any further processing until deletion is possible.</p>
|
||||
</section>
|
||||
|
||||
<section id="security">
|
||||
<h2>5. HOW DO WE KEEP YOUR INFORMATION SAFE?</h2>
|
||||
<p><em>In Short:</em> We aim to protect your personal information through a system of organizational and technical security measures.</p>
|
||||
<p>We have implemented appropriate and reasonable technical and organizational security measures designed to protect the security of any personal information we process. However, despite our safeguards and efforts to secure your information, no electronic transmission over the Internet or information storage technology can be guaranteed to be 100% secure. Transmission of personal information to and from our Services is at your own risk. You should only access the Services within a secure environment.</p>
|
||||
</section>
|
||||
|
||||
<section id="minors">
|
||||
<h2>6. DO WE COLLECT INFORMATION FROM MINORS?</h2>
|
||||
<p><em>In Short:</em> We do not knowingly collect data from or market to children under 18 years of age.</p>
|
||||
<p>We do not knowingly collect, solicit data from, or market to children under 18 years of age, nor do we knowingly sell such personal information. By using the Services, you represent that you are at least 18 or that you are the parent or guardian of such a minor and consent to such minor dependent’s use of the Services. If we learn that personal information from users less than 18 years of age has been collected, we will deactivate the account and take reasonable measures to promptly delete such data from our records. If you become aware of any data we may have collected from children under age 18, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
</section>
|
||||
|
||||
<section id="rights">
|
||||
<h2>7. WHAT ARE YOUR PRIVACY RIGHTS?</h2>
|
||||
<p><em>In Short:</em> You may review, change, or terminate your account at any time, depending on your country, province, or state of residence.</p>
|
||||
<p><strong>Withdrawing your consent:</strong> If we are relying on your consent to process your personal information (which may be express and/or implied consent depending on the applicable law), you have the right to withdraw your consent at any time. You can do so by contacting us using the details in the section "<a href="#contact">HOW CAN YOU CONTACT US ABOUT THIS NOTICE?</a>" below. This will not affect the lawfulness of the processing before its withdrawal, nor will it affect processing conducted in reliance on lawful processing grounds other than consent where permitted by law.</p>
|
||||
<p>If you have questions or comments about your privacy rights, email us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
</section>
|
||||
|
||||
<section id="dnt">
|
||||
<h2>8. CONTROLS FOR DO-NOT-TRACK FEATURES</h2>
|
||||
<p>Most web browsers and some mobile operating systems and applications include a Do-Not-Track ("DNT") setting you can activate to signal your privacy preference not to have data about your online browsing activities monitored and collected. At this stage, no uniform technology standard for recognizing and implementing DNT signals has been finalized. As such, we do not currently respond to DNT browser signals or any other mechanism that automatically communicates your choice not to be tracked online. If a standard for online tracking is adopted that we must follow in the future, we will inform you about that practice in a revised version of this Privacy Notice.</p>
|
||||
</section>
|
||||
|
||||
<section id="updates">
|
||||
<h2>9. DO WE MAKE UPDATES TO THIS NOTICE?</h2>
|
||||
<p><em>In Short:</em> Yes, we will update this notice as necessary to stay compliant with relevant laws.</p>
|
||||
<p>We may update this Privacy Notice from time to time. The updated version will be indicated by an updated "Revised" date at the top of this Privacy Notice. If we make material changes, we may notify you by prominently posting a notice of such changes or by directly sending you a notification. We encourage you to review this Privacy Notice frequently to stay informed of how we are protecting your information.</p>
|
||||
</section>
|
||||
|
||||
<section id="contact">
|
||||
<h2>10. HOW CAN YOU CONTACT US ABOUT THIS NOTICE?</h2>
|
||||
<address>
|
||||
Bali Interaktif Perkasa
|
||||
Park23 Creative Hub, Bali Interaktif Perkasa - Private Office
|
||||
Jl. Kediri 3rd Floor, Number 01 - 02, Tuban
|
||||
Badung, Bali 80361
|
||||
Indonesia
|
||||
</address>
|
||||
<p>Email: <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a></p>
|
||||
</section>
|
||||
|
||||
<section id="review">
|
||||
<h2>11. HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU?</h2>
|
||||
<p>You have the right to request access to the personal information we collect from you, details about how we have processed it, correct inaccuracies, or delete your personal information. You may also have the right to withdraw your consent to our processing of your personal information. These rights may be limited in some circumstances by applicable law.</p>
|
||||
<p>To make a request, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>© <span id="year"></span> Bali Interaktif Perkasa. All rights reserved.</p>
|
||||
</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
9
src/lib/getDatesInRange.ts
Normal file
9
src/lib/getDatesInRange.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export function getDatesInRange(startDate: Date, endDate: Date) {
|
||||
const dates = [];
|
||||
const currentDate = new Date(startDate);
|
||||
while (currentDate <= endDate) {
|
||||
dates.push(new Date(currentDate));
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
7
src/lib/urlCompleted.ts
Normal file
7
src/lib/urlCompleted.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function urlCompleted(url: string) {
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
return url
|
||||
} else {
|
||||
return `https://${url}`
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,27 @@ WibuServerPush.init({
|
||||
|
||||
export async function funSendWebPush({ sub, message }: { sub: { idUser: string, subscription: string }[], message: { body: string, title: string } }) {
|
||||
try {
|
||||
const subs: PushSubscription[] = sub.map((v) => JSON.parse(v.subscription)) as PushSubscription[]
|
||||
if (sub.length > 0) {
|
||||
const subs: PushSubscription[] = sub.map((v) => JSON.parse(v.subscription)) as PushSubscription[]
|
||||
|
||||
const kirim = await WibuServerPush.sendMany({
|
||||
subscriptions: subs as any,
|
||||
data: {
|
||||
body: message.body,
|
||||
title: message.title,
|
||||
link: "/home?cat=notification",
|
||||
variant: "notification"
|
||||
const kirim = await WibuServerPush.sendMany({
|
||||
subscriptions: subs as any,
|
||||
data: {
|
||||
body: message.body,
|
||||
title: message.title,
|
||||
link: "/home?cat=notification",
|
||||
variant: "notification"
|
||||
}
|
||||
})
|
||||
|
||||
if (kirim) {
|
||||
return { success: true, message: "Berhasil mengirim notifikasi" }
|
||||
}
|
||||
})
|
||||
|
||||
if (kirim) {
|
||||
return { success: true, message: "Berhasil mengirim notifikasi" }
|
||||
return { success: false, message: "Gagal mengirim notifikasi" }
|
||||
}
|
||||
|
||||
return { success: false, message: "Gagal mengirim notifikasi" }
|
||||
return { success: true, message: "Berhasil mengirim notifikasi [0]" }
|
||||
} catch (error) {
|
||||
console.error("Send web push notification error", error);
|
||||
return { success: false, message: "Gagal mengirim notifikasi" }
|
||||
|
||||
@@ -12,10 +12,10 @@ export const funGetAnnouncementById = async (path: string) => {
|
||||
|
||||
export const funCreateAnnouncement = async (data: IFormCreateAnnouncement) => {
|
||||
if (data.title == "" || data.desc == "")
|
||||
return { success: false, message: 'Silahkan lengkapi form tambah pengumuman' }
|
||||
return { success: false, message: 'Silakan lengkapi form tambah pengumuman' }
|
||||
|
||||
if (data.groups.length == 0)
|
||||
return { success: false, message: 'Silahkan pilih divisi penerima pengumuman' }
|
||||
return { success: false, message: 'Silakan pilih divisi penerima pengumuman' }
|
||||
|
||||
const response = await fetch("/api/announcement", {
|
||||
method: "POST",
|
||||
@@ -39,10 +39,10 @@ export const funDeleteAnnouncement = async (path: string) => {
|
||||
|
||||
export const funEditAnnouncement = async (path: string, data: IFormCreateAnnouncement) => {
|
||||
if (data.title == "" || data.desc == "")
|
||||
return { success: false, message: 'Silahkan lengkapi form edit pengumuman' }
|
||||
return { success: false, message: 'Silakan lengkapi form edit pengumuman' }
|
||||
|
||||
if (data.groups.length == 0)
|
||||
return { success: false, message: 'Silahkan pilih divisi penerima pengumuman' }
|
||||
return { success: false, message: 'Silakan pilih divisi penerima pengumuman' }
|
||||
|
||||
const response = await fetch(`/api/announcement/${path}`, {
|
||||
method: "PUT",
|
||||
|
||||
@@ -102,7 +102,7 @@ export default function CreateAnnouncement() {
|
||||
return false
|
||||
|
||||
if (memberValue.length == 0)
|
||||
return toast.error("Error! silahkan pilih divisi")
|
||||
return toast.error("Error! Silakan pilih divisi")
|
||||
|
||||
setOpen(true)
|
||||
}, 500)
|
||||
|
||||
@@ -180,7 +180,7 @@ function CreateBanner() {
|
||||
<Box mt={10}>
|
||||
{touched.image && !imgForm && (
|
||||
<Text size='sm' c={'red'}>
|
||||
Silahkan Pilih Gambar
|
||||
Silakan Pilih Gambar
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@@ -135,7 +135,7 @@ export default function CreateCalenderDivisionCaleder() {
|
||||
return false
|
||||
|
||||
if (memberValue.length == 0)
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
|
||||
setModal(true)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ export default function CreateUserCalender({ onClose }: { onClose: (val: any) =>
|
||||
|
||||
function onSubmit() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
member.set(selectedFiles)
|
||||
onClose(true)
|
||||
|
||||
@@ -92,7 +92,7 @@ export default function CreateUserDetailCalender() {
|
||||
async function onSubmit() {
|
||||
try {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
setLoadingSubmit(true)
|
||||
const res = await funAddMemberCalender(String(isDataCalender?.idCalendar), selectedFiles)
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function UpdateDivisionCalender() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toast.error("Terjadi kesalahan! Silahkan coba kembali");
|
||||
toast.error("Terjadi kesalahan! Silakan coba kembali");
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -84,7 +84,7 @@ export default function UpdateDivisionCalender() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toast.error("Terjadi kesalahan! Silahkan coba kembali");
|
||||
toast.error("Terjadi kesalahan! Silakan coba kembali");
|
||||
} finally {
|
||||
setModal(false)
|
||||
setLoadingModal(false)
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function UpdateListUsers({ onClose }: { onClose: (val: any) => vo
|
||||
|
||||
function onSubmit() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
member.set(selectedFiles)
|
||||
onClose(true)
|
||||
|
||||
@@ -101,7 +101,7 @@ export default function AddMemberDiscussionGeneral() {
|
||||
|
||||
function onCheck() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function ChooseUsersDiscussion({ grup, onClose }: { grup?: string
|
||||
|
||||
function onSubmit() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
member.set(selectedFiles)
|
||||
onClose(true)
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function FormCreateDiscussionGeneral() {
|
||||
return false
|
||||
|
||||
if (memberValue.length <= 1)
|
||||
return toast.error("Error! Silahkan pilih anggota lebih dari 1")
|
||||
return toast.error("Error! Silakan pilih anggota lebih dari 1")
|
||||
|
||||
setModal(true)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ export default function CreateAnggotaDivision() {
|
||||
|
||||
function onCheck() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ export default function CreateDivision() {
|
||||
return false
|
||||
|
||||
if (member.length == 0)
|
||||
return toast.error("Error! Silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
// if (member.length <= 1)
|
||||
// return toast.error("Error! Silahkan pilih anggota lebih dari 1")
|
||||
// return toast.error("Error! Silakan pilih anggota lebih dari 1")
|
||||
|
||||
setChooseAdmin(true)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function NavbarAdminDivision({ data, onSuccess }: { data: any, on
|
||||
|
||||
async function onSubmit() {
|
||||
if (value.length === 0) {
|
||||
return toast.error("Error! Silahkan pilih admin divisi")
|
||||
return toast.error("Error! Silakan pilih admin divisi")
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -53,7 +53,7 @@ export default function NavbarCreateUsers({ grup, onClose }: { grup?: string, on
|
||||
|
||||
function onSubmit() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
member.set(selectedFiles)
|
||||
onClose(true)
|
||||
|
||||
@@ -5,7 +5,6 @@ import NavbarDetailProject from "./ui/navbar_detail_project";
|
||||
import ProgressDetailProject from "./ui/progress_detail_project";
|
||||
import ListTugasDetailProject from "./ui/list_tugas_detail_project";
|
||||
import ListFileDetailProject from "./ui/list_file_detail_project";
|
||||
import LiatAnggotaDetailProject from "./ui/list_anggota_detail_project";
|
||||
import EditTaskProject from "./ui/edit_task_project";
|
||||
import EditDetailTaskProject from "./ui/edit_detail_task_project";
|
||||
import ListAnggotaDetailProject from "./ui/list_anggota_detail_project";
|
||||
@@ -15,6 +14,9 @@ import AddMemberDetailProject from "./ui/add_member_detail_project";
|
||||
import CreateProject from "./ui/create_project";
|
||||
import AddFileDetailProject from "./ui/add_file_detail_project";
|
||||
import WrapLayoutProject from "./ui/wrap_project";
|
||||
import ListLinkDetailProject from "./ui/list_link_detail_project";
|
||||
import AddReportProject from "./ui/add_report_project";
|
||||
import ListReportDetailProject from "./ui/list_report_project";
|
||||
|
||||
export { ViewDateEndTask }
|
||||
export { CreateUsersProject }
|
||||
@@ -31,4 +33,7 @@ export { CancelProject }
|
||||
export { AddMemberDetailProject }
|
||||
export { CreateProject }
|
||||
export { AddFileDetailProject }
|
||||
export { WrapLayoutProject }
|
||||
export { WrapLayoutProject }
|
||||
export { ListLinkDetailProject }
|
||||
export { AddReportProject }
|
||||
export { ListReportDetailProject }
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IFormAddDetailproject, IFormAddMemberProject, IFormDateProject, NewIFormDateProject } from "./type_project";
|
||||
import { IFormAddDetailproject, IFormAddMemberProject, NewIFormDateProject } from "./type_project";
|
||||
|
||||
|
||||
export const funGetAllProject = async (path?: string) => {
|
||||
@@ -49,8 +49,8 @@ export const funUpdateStatusProject = async (path: string, data: { status: numbe
|
||||
}
|
||||
|
||||
|
||||
export const funGetDetailProject = async (path: string) => {
|
||||
const response = await fetch(`/api/project/detail/${path}`);
|
||||
export const funGetDetailProject = async (path: string, kat?: string) => {
|
||||
const response = await fetch(`/api/project/detail/${path}${(kat) ? `?cat=${kat}` : ''}`);
|
||||
return await response.json().catch(() => null);
|
||||
}
|
||||
|
||||
@@ -122,6 +122,17 @@ export const funEditProject = async (path: string, data: { name: string }) => {
|
||||
return await response.json().catch(() => null);
|
||||
}
|
||||
|
||||
export const funEditReportProject = async (path: string, data: { report: string }) => {
|
||||
const response = await fetch(`/api/project/${path}/lainnya`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return await response.json().catch(() => null);
|
||||
}
|
||||
|
||||
|
||||
export const funDeleteFileProject = async (path: string) => {
|
||||
const response = await fetch(`/api/project/file/${path}`, {
|
||||
@@ -149,6 +160,17 @@ export const funAddFileProject = async (path: string, data: FormData) => {
|
||||
return await response.json().catch(() => null);
|
||||
};
|
||||
|
||||
export const funDeleteLinkProject = async (path: string, data: { idLink: string }) => {
|
||||
const response = await fetch(`/api/project/${path}/link`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return await response.json().catch(() => null);
|
||||
};
|
||||
|
||||
export const funDeleteProject = async (path: string) => {
|
||||
const response = await fetch(`/api/project/${path}/lainnya`, {
|
||||
method: "DELETE",
|
||||
@@ -159,3 +181,14 @@ export const funDeleteProject = async (path: string) => {
|
||||
return await response.json().catch(() => null);
|
||||
};
|
||||
|
||||
|
||||
export const funAddLinkProject = async (path: string, data: { link: string }) => {
|
||||
const response = await fetch(`/api/project/${path}/link`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return await response.json().catch(() => null);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,13 @@ export interface IDataFileProject {
|
||||
id: string
|
||||
name: string
|
||||
extension: string
|
||||
idStorage:string
|
||||
idStorage: string
|
||||
}
|
||||
|
||||
|
||||
export interface IDataLinkProject {
|
||||
id: string
|
||||
link: string
|
||||
}
|
||||
|
||||
export interface IDataMemberProject {
|
||||
@@ -46,10 +52,11 @@ export interface IFormDateProject {
|
||||
title: string,
|
||||
}
|
||||
|
||||
export interface NewIFormDateProject{
|
||||
export interface NewIFormDateProject {
|
||||
dateStart: string,
|
||||
dateEnd: string,
|
||||
title: string,
|
||||
dataDetail: any[]
|
||||
}
|
||||
|
||||
export interface IFormMemberProject {
|
||||
@@ -62,7 +69,8 @@ export interface IFormMemberProject {
|
||||
export interface IFormAddDetailproject {
|
||||
dateStart: string,
|
||||
dateEnd: string,
|
||||
name: string
|
||||
name: string,
|
||||
dataDetail: any[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client"
|
||||
import { getDatesInRange } from '@/lib/getDatesInRange';
|
||||
import { keyWibu, LayoutNavbarNew, TEMA } from '@/module/_global';
|
||||
import LayoutModal from '@/module/_global/layout/layout_modal';
|
||||
import { useHookstate } from '@hookstate/core';
|
||||
@@ -11,6 +12,7 @@ import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useWibuRealtime } from 'wibu-realtime';
|
||||
import { funCreateDetailProject } from '../lib/api_project';
|
||||
import { ModalAddDetailTaskProject } from './modal_add_detail_task_project';
|
||||
|
||||
export default function AddDetailTaskProject() {
|
||||
const [value, setValue] = useState<[Date | null, Date | null]>([null, null]);
|
||||
@@ -21,6 +23,8 @@ export default function AddDetailTaskProject() {
|
||||
const param = useParams<{ id: string }>()
|
||||
const tema = useHookstate(TEMA)
|
||||
const [acuan, setAcuan] = useState(false)
|
||||
const [openModalDetailTask, setOpenModalDetailTask] = useState(false)
|
||||
const [dataDetail, setDataDetail] = useState<any>([])
|
||||
const [touched, setTouched] = useState({
|
||||
title: false,
|
||||
date: false
|
||||
@@ -33,10 +37,16 @@ export default function AddDetailTaskProject() {
|
||||
async function onSubmit() {
|
||||
try {
|
||||
setLoadingModal(true)
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
date: moment(v.date).format("YYYY-MM-DD"),
|
||||
}))
|
||||
|
||||
const res = await funCreateDetailProject(param.id, {
|
||||
name,
|
||||
dateStart: (value[0] != null) ? moment(value[0]).format('YYYY-MM-DD') : moment(new Date).format('YYYY-MM-DD'),
|
||||
dateEnd: (value[1] != null) ? moment(value[1]).format('YYYY-MM-DD') : moment(new Date).format('YYYY-MM-DD'),
|
||||
dataDetail: dataDetailFix
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
@@ -94,8 +104,15 @@ export default function AddDetailTaskProject() {
|
||||
const array = val.split(",")
|
||||
if (array[0] == '' || array[1] == '') {
|
||||
setTouched({ ...touched, date: true })
|
||||
setDataDetail([])
|
||||
} else {
|
||||
setTouched({ ...touched, date: false })
|
||||
const datanya = getDatesInRange(value[0]!, value[1]!)
|
||||
setDataDetail(datanya.map((data: any) => ({
|
||||
date: data,
|
||||
timeStart: null,
|
||||
timeEnd: null
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,7 +136,6 @@ export default function AddDetailTaskProject() {
|
||||
style={{ borderRadius: 10, border: `1px solid ${"#D6D8F6"}` }}
|
||||
>
|
||||
<DatePicker
|
||||
styles={{}}
|
||||
type="range"
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
@@ -160,6 +176,16 @@ export default function AddDetailTaskProject() {
|
||||
? <Text size="sm" c={"red"}>Tanggal Tidak Boleh Kosong</Text>
|
||||
: <></>
|
||||
}
|
||||
<Button
|
||||
variant="light"
|
||||
size="compact-md"
|
||||
radius={5}
|
||||
onClick={() => { setOpenModalDetailTask(true) }}
|
||||
mt={5}
|
||||
disabled={value[0] == null || value[1] == null || touched.date}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
<Stack pt={15} pb={100}>
|
||||
<TextInput
|
||||
styles={{
|
||||
@@ -201,6 +227,15 @@ export default function AddDetailTaskProject() {
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<ModalAddDetailTaskProject
|
||||
open={openModalDetailTask}
|
||||
onClose={() => setOpenModalDetailTask(false)}
|
||||
data={dataDetail}
|
||||
onSubmit={(data) => {
|
||||
setDataDetail(data)
|
||||
setOpenModalDetailTask(false)
|
||||
}}
|
||||
/>
|
||||
|
||||
<LayoutModal loading={loadingModal} opened={openModal} onClose={() => setOpenModal(false)}
|
||||
description="Apakah Anda yakin ingin menambahkan tugas?"
|
||||
|
||||
@@ -171,7 +171,7 @@ export default function AddFileDetailProject() {
|
||||
if (fileForm.length > 0) {
|
||||
setOpenModal(true)
|
||||
} else {
|
||||
toast.error("Silahkan pilih file yang akan diupload")
|
||||
toast.error("Silakan pilih file yang akan diupload")
|
||||
}
|
||||
}}>
|
||||
Simpan
|
||||
|
||||
@@ -91,7 +91,7 @@ export default function AddMemberDetailProject() {
|
||||
|
||||
function onVerifikasi() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
|
||||
setOpenModal(true)
|
||||
|
||||
157
src/module/project/ui/add_report_project.tsx
Normal file
157
src/module/project/ui/add_report_project.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
"use client"
|
||||
import { keyWibu, LayoutNavbarNew, TEMA } from '@/module/_global';
|
||||
import LayoutModal from '@/module/_global/layout/layout_modal';
|
||||
import { useHookstate } from '@hookstate/core';
|
||||
import { Box, Button, rem, Skeleton, Stack, Textarea } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useWibuRealtime } from 'wibu-realtime';
|
||||
import { funEditReportProject, funGetOneProjectById } from '../lib/api_project';
|
||||
|
||||
export default function AddReportProject() {
|
||||
const router = useRouter()
|
||||
const [report, setReport] = useState("")
|
||||
const [openModal, setOpenModal] = useState(false)
|
||||
const param = useParams<{ id: string }>()
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [loadingSubmit, setLoadingSubmit] = useState(false)
|
||||
const tema = useHookstate(TEMA)
|
||||
const [touched, setTouched] = useState({
|
||||
report: false,
|
||||
});
|
||||
const [dataRealTime, setDataRealtime] = useWibuRealtime({
|
||||
WIBU_REALTIME_TOKEN: keyWibu,
|
||||
project: "sdm"
|
||||
})
|
||||
|
||||
async function onSubmit() {
|
||||
try {
|
||||
setLoadingSubmit(true)
|
||||
const res = await funEditReportProject(param.id, { report })
|
||||
if (res.success) {
|
||||
setDataRealtime([{
|
||||
category: "project-report",
|
||||
id: param.id,
|
||||
}])
|
||||
toast.success(res.message)
|
||||
router.push("./")
|
||||
} else {
|
||||
toast.error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toast.error("Gagal mengedit Laporan Kegiatan, coba lagi nanti")
|
||||
} finally {
|
||||
setLoadingSubmit(false)
|
||||
setOpenModal(false)
|
||||
}
|
||||
}
|
||||
|
||||
function onCheck() {
|
||||
if (report == "") {
|
||||
setTouched({ ...touched, report: true })
|
||||
return false
|
||||
}
|
||||
setOpenModal(true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
function onValidation(kategori: string, val: string) {
|
||||
if (kategori == 'report') {
|
||||
setReport(val)
|
||||
if (val === "") {
|
||||
setTouched({ ...touched, report: true })
|
||||
} else {
|
||||
setTouched({ ...touched, report: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getOneData() {
|
||||
try {
|
||||
setLoading(true)
|
||||
const res = await funGetOneProjectById(param.id, 'data');
|
||||
if (res.success) {
|
||||
setReport(res.data.report);
|
||||
} else {
|
||||
toast.error(res.message);
|
||||
}
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Gagal mendapatkan data Kegiatan, coba lagi nanti");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
useShallowEffect(() => {
|
||||
getOneData();
|
||||
}, [param.id])
|
||||
|
||||
|
||||
return (
|
||||
<Box >
|
||||
<LayoutNavbarNew back="" title={"Laporan Kegiatan"} menu />
|
||||
<Box p={20}>
|
||||
<Stack pt={15}>
|
||||
{loading ?
|
||||
<Skeleton height={150} mt={20} radius={10} />
|
||||
:
|
||||
<Textarea placeholder="Laporan Kegiatan" label="Laporan Kegiatan" size="md" radius={10}
|
||||
value={report}
|
||||
required
|
||||
error={
|
||||
touched.report && (
|
||||
report == "" ? "Laporan Tidak Boleh Kosong" : null
|
||||
)
|
||||
}
|
||||
onChange={(e) => { onValidation('report', e.currentTarget.value) }}
|
||||
styles={{
|
||||
input: {
|
||||
height: "30vh"
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</Stack>
|
||||
</Box>
|
||||
<Box pos={'fixed'} bottom={0} p={rem(20)} w={"100%"} style={{
|
||||
maxWidth: rem(550),
|
||||
zIndex: 999,
|
||||
backgroundColor: `${tema.get().bgUtama}`,
|
||||
}}>
|
||||
{loading ?
|
||||
<Skeleton height={50} radius={30} />
|
||||
:
|
||||
<Button
|
||||
c={"white"}
|
||||
bg={Object.values(touched).some((v) => v == true) || report == "" || report == null ? 'gray' : tema.get().utama}
|
||||
size="lg"
|
||||
radius={30}
|
||||
fullWidth
|
||||
onClick={() => { onCheck() }}
|
||||
disabled={Object.values(touched).some((v) => v == true) || report == "" || report == null ? true : false}
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
}
|
||||
</Box>
|
||||
|
||||
|
||||
<LayoutModal opened={openModal} loading={loadingSubmit} onClose={() => setOpenModal(false)}
|
||||
description="Apakah Anda yakin ingin mengedit Laporan Kegiatan ini?"
|
||||
onYes={(val) => {
|
||||
if (val) {
|
||||
onSubmit()
|
||||
} else {
|
||||
setOpenModal(false)
|
||||
}
|
||||
}} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
import { getDatesInRange } from "@/lib/getDatesInRange";
|
||||
import { LayoutNavbarNew, TEMA } from "@/module/_global";
|
||||
import { useHookstate } from "@hookstate/core";
|
||||
import { ActionIcon, Box, Button, Flex, Group, rem, SimpleGrid, Stack, Text, TextInput } from "@mantine/core";
|
||||
@@ -9,6 +10,7 @@ import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { HiChevronLeft } from "react-icons/hi2";
|
||||
import { NewIFormDateProject } from "../lib/type_project";
|
||||
import { ModalAddDetailTaskProject } from "./modal_add_detail_task_project";
|
||||
|
||||
|
||||
export default function ViewDateEndTask({ onClose, onSet }: { onClose: (val: boolean) => void, onSet: (val: NewIFormDateProject) => void }) {
|
||||
@@ -16,6 +18,8 @@ export default function ViewDateEndTask({ onClose, onSet }: { onClose: (val: boo
|
||||
const [title, setTitle] = useState("")
|
||||
const tema = useHookstate(TEMA)
|
||||
const [acuan, setAcuan] = useState(false)
|
||||
const [openModalDetailTask, setOpenModalDetailTask] = useState(false)
|
||||
const [dataDetail, setDataDetail] = useState<any[]>([])
|
||||
const [touched, setTouched] = useState({
|
||||
title: false,
|
||||
date: false
|
||||
@@ -28,10 +32,16 @@ export default function ViewDateEndTask({ onClose, onSet }: { onClose: (val: boo
|
||||
if (title == "")
|
||||
return toast.error("Error! harus memasukkan judul tugas")
|
||||
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
date: moment(v.date).format("YYYY-MM-DD"),
|
||||
}))
|
||||
|
||||
onSet({
|
||||
dateStart: moment(value[0]).format('YYYY-MM-DD'),
|
||||
dateEnd: moment(value[1]).format('YYYY-MM-DD'),
|
||||
title: title
|
||||
title,
|
||||
dataDetail: dataDetailFix
|
||||
})
|
||||
}
|
||||
|
||||
@@ -72,8 +82,15 @@ export default function ViewDateEndTask({ onClose, onSet }: { onClose: (val: boo
|
||||
const array = val.split(",")
|
||||
if (array[0] == '' || array[1] == '') {
|
||||
setTouched({ ...touched, date: true })
|
||||
setDataDetail([])
|
||||
} else {
|
||||
setTouched({ ...touched, date: false })
|
||||
const datanya = getDatesInRange(value[0]!, value[1]!)
|
||||
setDataDetail(datanya.map((data: any) => ({
|
||||
date: data,
|
||||
timeStart: null,
|
||||
timeEnd: null
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,6 +161,16 @@ export default function ViewDateEndTask({ onClose, onSet }: { onClose: (val: boo
|
||||
? <Text size="sm" c={"red"}>Tanggal Tidak Boleh Kosong</Text>
|
||||
: <></>
|
||||
}
|
||||
<Button
|
||||
variant="light"
|
||||
size="compact-md"
|
||||
radius={5}
|
||||
onClick={() => { setOpenModalDetailTask(true) }}
|
||||
mt={5}
|
||||
disabled={value[0] == null || value[1] == null || touched.date}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
<Stack pt={15} pb={100}>
|
||||
<TextInput
|
||||
styles={{
|
||||
@@ -184,6 +211,16 @@ export default function ViewDateEndTask({ onClose, onSet }: { onClose: (val: boo
|
||||
Simpan
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<ModalAddDetailTaskProject
|
||||
open={openModalDetailTask}
|
||||
onClose={() => setOpenModalDetailTask(false)}
|
||||
data={dataDetail}
|
||||
onSubmit={(data) => {
|
||||
setDataDetail(data)
|
||||
setOpenModalDetailTask(false)
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -142,10 +142,10 @@ export default function CreateProject() {
|
||||
return false
|
||||
|
||||
if (dataTask.length == 0)
|
||||
return toast.error("Error! silahkan tambahkan tugas")
|
||||
return toast.error("Error! Silakan tambahkan tugas")
|
||||
|
||||
if (memberValue.length <= 1)
|
||||
return toast.error("Error! Silahkan pilih anggota lebih dari 1")
|
||||
return toast.error("Error! Silakan pilih anggota lebih dari 1")
|
||||
|
||||
setModal(true)
|
||||
}
|
||||
@@ -299,7 +299,7 @@ export default function CreateProject() {
|
||||
setIndexDelTask(i)
|
||||
setOpenDrawerTask(true)
|
||||
}}>
|
||||
<ResultsDateAndTask dateStart={v.dateStart} dateEnd={v.dateEnd} title={v.title} />
|
||||
<ResultsDateAndTask dateStart={v.dateStart} dateEnd={v.dateEnd} title={v.title} dataDetail={v.dataDetail} />
|
||||
</Box>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function CreateUsersProject({ grup, onClose }: { grup?: string, o
|
||||
|
||||
function onSubmit() {
|
||||
if (selectedFiles.length == 0) {
|
||||
return toast.error("Error! silahkan pilih anggota")
|
||||
return toast.error("Error! Silakan pilih anggota")
|
||||
}
|
||||
member.set(selectedFiles)
|
||||
onClose(true)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client"
|
||||
import { getDatesInRange } from '@/lib/getDatesInRange';
|
||||
import { keyWibu, LayoutNavbarNew, TEMA } from '@/module/_global';
|
||||
import LayoutModal from '@/module/_global/layout/layout_modal';
|
||||
import { useHookstate } from '@hookstate/core';
|
||||
@@ -11,6 +12,7 @@ import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useWibuRealtime } from 'wibu-realtime';
|
||||
import { funEditDetailProject, funGetDetailProject } from '../lib/api_project';
|
||||
import { ModalAddDetailTaskProject } from './modal_add_detail_task_project';
|
||||
|
||||
export default function EditDetailTaskProject() {
|
||||
const [value, setValue] = useState<[Date | null, Date | null]>([null, null]);
|
||||
@@ -19,6 +21,8 @@ export default function EditDetailTaskProject() {
|
||||
const param = useParams<{ id: string }>()
|
||||
const [openModal, setOpenModal] = useState(false)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [openModalDetailTask, setOpenModalDetailTask] = useState(false)
|
||||
const [dataDetail, setDataDetail] = useState<any>([])
|
||||
const [loadingModal, setLoadingModal] = useState(false)
|
||||
const tema = useHookstate(TEMA)
|
||||
const [touched, setTouched] = useState({
|
||||
@@ -40,11 +44,15 @@ export default function EditDetailTaskProject() {
|
||||
|
||||
try {
|
||||
setLoadingModal(true)
|
||||
const dataDetailFix = dataDetail.map((v: any) => ({
|
||||
...v,
|
||||
date: moment(v.date).format("YYYY-MM-DD"),
|
||||
}))
|
||||
const res = await funEditDetailProject(param.id, {
|
||||
title: name,
|
||||
dateStart: moment(value[0]).format('YYYY-MM-DD'),
|
||||
dateEnd: moment(value[1]).format('YYYY-MM-DD'),
|
||||
|
||||
dataDetail: dataDetailFix
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
@@ -77,6 +85,18 @@ export default function EditDetailTaskProject() {
|
||||
new Date(moment(res.data.dateStart).format('YYYY-MM-DD')),
|
||||
new Date(moment(res.data.dateEnd).format('YYYY-MM-DD')),
|
||||
])
|
||||
|
||||
const res2 = await funGetDetailProject(param.id, 'detailTask');
|
||||
if (res2.data.length == 0) {
|
||||
const datanya = getDatesInRange(new Date(moment(res.data.dateStart).format('YYYY-MM-DD')) , new Date(moment(res.data.dateEnd).format('YYYY-MM-DD')))
|
||||
setDataDetail(datanya.map((data: any) => ({
|
||||
date: data,
|
||||
timeStart: null,
|
||||
timeEnd: null
|
||||
})))
|
||||
} else {
|
||||
setDataDetail(res2.data)
|
||||
}
|
||||
} else {
|
||||
toast.error(res.message);
|
||||
}
|
||||
@@ -112,8 +132,15 @@ export default function EditDetailTaskProject() {
|
||||
const array = val.split(",")
|
||||
if (array[0] == '' || array[1] == '') {
|
||||
setTouched({ ...touched, date: true })
|
||||
setDataDetail([])
|
||||
} else {
|
||||
setTouched({ ...touched, date: false })
|
||||
const datanya = getDatesInRange(value[0]!, value[1]!)
|
||||
setDataDetail(datanya.map((data: any) => ({
|
||||
date: data,
|
||||
timeStart: null,
|
||||
timeEnd: null
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,6 +214,16 @@ export default function EditDetailTaskProject() {
|
||||
? <Text size="sm" c={"red"}>Tanggal Tidak Boleh Kosong</Text>
|
||||
: <></>
|
||||
}
|
||||
<Button
|
||||
variant="light"
|
||||
size="compact-md"
|
||||
radius={5}
|
||||
onClick={() => { setOpenModalDetailTask(true) }}
|
||||
mt={5}
|
||||
disabled={value[0] == null || value[1] == null || touched.date}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
<Stack pt={15} pb={100}>
|
||||
{loading ?
|
||||
<Skeleton height={40} mt={20} radius={10} />
|
||||
@@ -234,6 +271,17 @@ export default function EditDetailTaskProject() {
|
||||
}
|
||||
</Box>
|
||||
|
||||
|
||||
<ModalAddDetailTaskProject
|
||||
open={openModalDetailTask}
|
||||
onClose={() => setOpenModalDetailTask(false)}
|
||||
data={dataDetail}
|
||||
onSubmit={(data) => {
|
||||
setDataDetail(data)
|
||||
setOpenModalDetailTask(false)
|
||||
}}
|
||||
/>
|
||||
|
||||
<LayoutModal loading={loadingModal} opened={openModal} onClose={() => setOpenModal(false)}
|
||||
description="Apakah Anda yakin ingin mengubah data?"
|
||||
onYes={(val) => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user