135 Commits

Author SHA1 Message Date
3ab2566a89 update 2025-10-27 10:32:54 +08:00
9573c1472a Merge pull request 'upd: api mobile status saat error' (#67) from amalia/16-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#67
2025-10-16 14:56:17 +08:00
ed2c9495c3 upd: api mobile status saat error 2025-10-16 14:53:23 +08:00
1b8bfebf4f Merge pull request 'amalia/15-okt-25' (#65) from amalia/15-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#65
2025-10-15 14:56:29 +08:00
10b9037fda upd: api version 2025-10-15 14:52:17 +08:00
4a4be31921 upd: api website dan mobile
Deskripsi:
- update order komentar pada mobile dan website pada fitur diskusi umum dan diskusi divisi

No Issues
2025-10-15 14:51:58 +08:00
9b48fe56fd Merge pull request 'amalia/14-okt-25' (#63) from amalia/14-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#63
2025-10-14 17:32:25 +08:00
18023807cd upd: api version app 2025-10-14 15:14:08 +08:00
bd1758ce32 upd: api diskusi komentar
deskripsi:
- api komentar pada website diskusi umum dan diskusi divisi

NO Issues
2025-10-14 15:13:51 +08:00
878b3aa278 upd: komentar diskusi
- api mobile hapus komentar diskusi umum dan diskusi divisi
- api mobile edit komentar diskusi dumum dan diskusi divisi

No Issues
2025-10-14 15:00:39 +08:00
f02ffc58ad Merge pull request 'upd: komentar diskusi' (#62) from amalia/13-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#62
2025-10-13 17:22:18 +08:00
3d5149cbba upd: komentar diskusi
- Deskripsi:
- upd database
- tampilan api mobile komentar diskusi umum dan diskusi divisi

No Issues
2025-10-13 17:19:20 +08:00
411037ec4a Merge pull request 'fix : api home' (#60) from amalia/08-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#60
2025-10-08 16:20:18 +08:00
66ba6dfa91 fix : api home
Deskripsi:
- update api home > kegiatan terupdate order by updatedate
- api version app

No Issues
2025-10-08 16:14:30 +08:00
389f115923 Merge pull request 'amalia/07-okt-25' (#58) from amalia/07-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#58
2025-10-07 17:42:53 +08:00
2251818908 upd: api version 2025-10-07 17:11:18 +08:00
b625150eb5 upd: api home website
Deskripsi:
- update home api website jadi sama kyk mobile

NO Issues
2025-10-07 17:09:36 +08:00
bae91db60a upd: penerima notifikasi
Deskripsi:
- pembuat data mendapat notifikasi saat user memberi komentar walaupun pembuat data bukan merupakan anggota dari diskusi umum maupun anggota divisi
- diskusi umum dan diskusi divis

No Issues
2025-10-07 16:36:34 +08:00
150151e823 upd: order tugas
Deskripsi:
- order tugas pada tugas divisi dan kegiatan

NO Issues'
2025-10-07 15:09:20 +08:00
d1a591a63a upd: api mobile
Deskripsi:
- check nama divisi

No Issues
2025-10-07 12:01:19 +08:00
7e80a1f311 Merge pull request 'fix:api mobile' (#57) from amalia/06-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#57
2025-10-06 17:23:56 +08:00
b648735b06 fix:api mobile
Deskripsi:
- filter notif duplikat pada fitur pengumuman, diskusi umum, diskusi divisi, divisi, kegiatan dan tugas divisi

NO Issues
2025-10-06 17:08:07 +08:00
a3d8bf1e92 Merge pull request 'upd: home api mobile' (#56) from amalia/03-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#56
2025-10-03 17:32:20 +08:00
c2c52ed5fd upd: home api mobile 2025-10-03 16:53:31 +08:00
3fd9395fc1 Merge pull request 'amalia/02-okt-25' (#55) from amalia/02-okt-25 into join
Reviewed-on: bip/sistem-desa-mandiri#55
2025-10-02 17:43:24 +08:00
1f259a409b upd: api mobile
Deskripsi:
- home > progress, kegiatan updated, divisi, dokumen, event, diskusi

NO Issues
2025-10-02 17:39:10 +08:00
55c932ab89 Merge pull request 'join' (#54) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#54
2025-09-30 15:57:27 +08:00
b4ee1bc996 Merge pull request 'upd: notif insert' (#53) from amalia/30-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#53
2025-09-30 15:56:23 +08:00
9a6a4d66df upd: notif insert
Deskripsi:
- mengganti kalimat notifikasi sesuai dengan content yg diinputkan
- upd api version

No Issues
2025-09-30 14:40:37 +08:00
6910f8fdff Merge pull request 'upd : typo kata' (#52) from amalia/29-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#52
2025-09-29 17:36:27 +08:00
e20f5c11e4 upd : typo kata
Deskripsi:
- Silahkan menjadi silakan :: tanpa h

No Issues
2025-09-29 17:23:44 +08:00
8e18ad0e77 Merge pull request 'join' (#51) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#51
2025-09-29 10:56:31 +08:00
6e30190161 Merge pull request 'upd: api ai' (#50) from amalia/29-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#50
2025-09-29 10:55:41 +08:00
67d338ac84 upd: api ai
Deskripsi:
- perbaiki get data
- api ai data desa
- api ai version app

No Issues
2025-09-29 10:54:44 +08:00
f7e84314fb Merge pull request 'join' (#49) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#49
2025-09-23 11:33:47 +08:00
5fc34eb49b Merge pull request 'upd: public privacy' (#48) from amalia/23-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#48
2025-09-23 11:33:19 +08:00
bbd610910d upd: public privacy 2025-09-23 11:29:16 +08:00
7f8214172c Merge pull request 'join' (#47) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#47
2025-09-22 16:39:48 +08:00
7af2f8044e Merge pull request 'upd: privacy-policy' (#46) from amalia/22-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#46
2025-09-22 16:39:19 +08:00
0eba2209d1 upd: privacy-policy
Deskripsi:
- page privacy policy
- update api version app

NO Issues
2025-09-22 16:36:47 +08:00
c3ce77b0dc Merge pull request 'join' (#45) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#45
2025-09-22 16:15:25 +08:00
4acd7f901a Merge pull request 'amalia/22-sept-25' (#44) from amalia/22-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#44
2025-09-22 15:46:58 +08:00
4064497794 upd: api version 2025-09-22 15:45:17 +08:00
ae3131ecf8 upd : privacy 2025-09-22 15:43:11 +08:00
9c07375015 upd: swagger api ai 2025-09-22 15:31:23 +08:00
4b1d2e28dc upd: api ai report divisi
Deskripsi:
- update api ai laporan divisi

NO Issues
2025-09-22 15:31:02 +08:00
fdfa526d8c upd: api ai user
Deskripsi:
- list user
- detail user

No Issues
2025-09-22 11:43:26 +08:00
862ee0001f Merge pull request 'amalia/19-sept-25' (#43) from amalia/19-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#43
2025-09-19 17:59:25 +08:00
09d1088fac upd: swagger watcher 2025-09-19 16:48:22 +08:00
bbe016c03d upd: api ai
Deskripsi:
- list task
- detail task

No Issues
2025-09-19 16:47:52 +08:00
c51692079e upd: api ai project
Deskripsi:
- list project

- detail project

No Issues'
2025-09-19 12:33:31 +08:00
fbfdc21b9d upd: api ai positision
Deskripsi:
- list position

No Issues
2025-09-19 11:42:45 +08:00
51b39396ec upd: api ai group
Deskripsi:
- list group

NO Issues
2025-09-19 11:08:19 +08:00
18589b7de7 upd: api ai document divisi
Deskripsi:
- list dokumen dan file divisi

NO Issues
2025-09-19 10:56:02 +08:00
e49fb11c94 Merge pull request 'amalia/17-sept-25' (#42) from amalia/17-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#42
2025-09-17 17:33:33 +08:00
d3f4478bb1 upd: api ai
Deskripsi:
- document divisi
- swagger watcher

nb: blm selesai

NO Issues
2025-09-17 17:32:43 +08:00
006754a337 upd: api ai
Deskripsi:
- list divisi
- detail divisi

No Issues
2025-09-17 14:29:53 +08:00
54d708d109 upd: api ai diskusi umum
Deskripsi:
- api ai list diskusi umum
- api ai detail diskusi umum

NO Issues
2025-09-17 10:58:48 +08:00
6ed16d05b9 Merge pull request 'amalia/16-sept-25' (#41) from amalia/16-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#41
2025-09-16 17:42:13 +08:00
b78013c160 upd: api ai swager 2025-09-16 17:32:55 +08:00
bef4dd1969 upd: api ai
Deskripsi:
- api ai get list discussion general
- api ai detail discussion general

nb : belm selesai

No Issues
2025-09-16 17:31:46 +08:00
f10b87f0f2 upd : api ai diskusi divisi
Deskripsi:
- list diskusi divisi
- detail diskusi divisi

No Issues"
git status
2025-09-16 17:10:03 +08:00
2e4eaaec95 api ai
Deskripsi:
- api get list calendar
- api get detail calendar

No Issues
2025-09-16 15:35:47 +08:00
f87b99f704 upd: api ai
Deskripsi
:
- update banner api ai

No Issues
2025-09-16 14:24:58 +08:00
83085418ed upd: pengumuman
deskripsiL
:
- update api ai pengumuman

No Issues
2025-09-16 14:23:15 +08:00
f8ece570b1 Merge pull request 'upd: api ai' (#40) from amalia/15-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#40
2025-09-15 17:40:18 +08:00
648f23c760 upd: api ai
Deskripsi:
- api ai list pengumuman
- api ai detail pengumuman
- api ai list banner : blm selesai

No Issues
2025-09-15 17:38:13 +08:00
3af2a2ef05 Merge pull request 'join' (#39) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#39
2025-09-02 17:06:20 +08:00
cacc8c72b3 Merge pull request 'upd: login tanpa otp' (#38) from amalia/02-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#38
2025-09-02 17:04:49 +08:00
dfa7b571f1 upd: login tanpa otp
Deskripsi:
- struktur db
- update api
- update api version app

No Issues
2025-09-02 14:38:32 +08:00
2e4ab4f861 Merge pull request 'join' (#37) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#37
2025-09-01 17:01:02 +08:00
a533f3b085 Merge pull request 'amalia/01-sept-25' (#36) from amalia/01-sept-25 into join
Reviewed-on: bip/sistem-desa-mandiri#36
2025-09-01 17:00:23 +08:00
4810fecb10 upd: api mobile
Desksripsi
2025-09-01 16:37:29 +08:00
3af4d84e55 upd: api version 2025-09-01 15:41:06 +08:00
f3fa9eab99 upd login api mobile 2025-09-01 15:40:12 +08:00
96088dad07 Merge pull request 'join' (#35) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#35
2025-08-29 17:06:23 +08:00
303f646ff1 Merge pull request 'amalia/29-agustus-25' (#34) from amalia/29-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#34
2025-08-29 17:05:26 +08:00
dce9366fab upd: api version 2025-08-29 16:58:25 +08:00
e345e97023 upd: nama file saat upload di semua fitur mobile 2025-08-29 14:36:48 +08:00
d114b9b06d Merge pull request 'join' (#33) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#33
2025-08-28 17:07:25 +08:00
d7a90db6a7 Merge pull request 'fix : firebase notification' (#32) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#32
2025-08-28 17:06:39 +08:00
e48ff58c48 fix : firebase notification
Deskripsi:
- empty array token undefined > semua fitur

- update api version

No Issues
2025-08-28 17:04:09 +08:00
4a57ffd69c Merge pull request 'join' (#31) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#31
2025-08-28 16:51:00 +08:00
cc72323891 Merge pull request 'upd: firebase emty undefined' (#30) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#30
2025-08-28 16:50:31 +08:00
ed133a7452 upd: firebase emty undefined 2025-08-28 16:47:53 +08:00
5f81128a97 Merge pull request 'join' (#29) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#29
2025-08-28 16:40:43 +08:00
62684557ba Merge pull request 'fix: error send notification' (#28) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#28
2025-08-28 16:40:03 +08:00
562470bcd3 fix: error send notification
Deskripsi:
- fix send web notification > empty array
- console.log xsendmany firebase notification
- upd version app

No Issues
2025-08-28 16:36:00 +08:00
0987978cb4 Merge pull request 'join' (#27) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#27
2025-08-28 15:22:36 +08:00
b5f1c2ebdd Merge pull request 'upd: api error' (#26) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#26
2025-08-28 15:21:57 +08:00
ca699f1430 upd: api error 2025-08-28 15:20:09 +08:00
a402d8ba51 Merge pull request 'join' (#25) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#25
2025-08-28 15:12:09 +08:00
a0fbfb39b3 Merge pull request 'upd : data notif kosong' (#24) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#24
2025-08-28 15:11:28 +08:00
1621e95af2 upd : data notif kosong
Deskripsi:
- filter data notif dg iduser = undefined

No Issues
2025-08-28 15:08:14 +08:00
cb50197158 Merge pull request 'join' (#23) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#23
2025-08-28 14:10:15 +08:00
523826c376 Merge pull request 'upd: notifikasi data' (#22) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#22
2025-08-28 14:08:02 +08:00
e5eb2e1cc2 upd: notifikasi data
Deskripsi:
- filter data iduser = undefined

No Issues
2025-08-28 14:06:56 +08:00
25b37909f5 Merge pull request 'join' (#21) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#21
2025-08-28 11:31:47 +08:00
772439031d Merge pull request 'upd: api mobile' (#20) from amalia/28-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#20
2025-08-28 11:31:13 +08:00
3bbfadb45e upd: api mobile
Deskripsi:
- update validasi register user yg udh ada

No Issues
2025-08-28 11:27:30 +08:00
4ff905eba9 Merge pull request 'join' (#19) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#19
2025-08-28 10:24:11 +08:00
bda9b4ba85 Merge pull request 'amalia/27-agustus-25' (#18) from amalia/27-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#18
2025-08-27 17:35:11 +08:00
215fb59ec7 upd: api version 2025-08-27 17:10:07 +08:00
10e0619789 upd : api mobile jabatan
Deskripsi:
- get list data idgroup
- edit jabatan > ketika sudah ada jabtan yg sama

No Issues
2025-08-27 17:08:47 +08:00
60c4a11d64 Merge pull request 'join' (#17) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#17
2025-08-22 10:45:58 +08:00
99b64e1a70 Merge pull request 'amalia/21-agustus-25' (#16) from amalia/21-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#16
2025-08-21 17:36:52 +08:00
90e61422cf upd: update status project
Deskripsi;
- update status project saat menambahkan detail task project ketika project sudah berstatus selesai menjadi sedang dikerjakan

No
Issues
2025-08-21 15:46:01 +08:00
20032301e8 fix : firebase
Deskripsi
:
- fix error emty token firebase

NO Issues
2025-08-21 15:31:27 +08:00
19c99534c5 Merge pull request 'amalia/20-agustus-25' (#15) from amalia/20-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#15
2025-08-20 17:22:18 +08:00
6147223b34 upd: api version 2025-08-20 17:13:30 +08:00
d000910b9f upd : api mobile detail tugas task divisi
Deskripsi:
- api get list detail tugas task divisi
- api tambah detail tugas task divisi
- api edit detail tugas task divisi
- api tambah data task divisi > detail tugas

No Issues
2025-08-20 17:13:07 +08:00
499c7441ad upd: api mobile project fitur baru
Deskripsi:
- api mobile get data detail tugas project
- api mobile tambah detail tugas project
- api mobile edit detail tugas project
- api mobile tambah data project > detail tugas

No Issues
2025-08-20 15:18:35 +08:00
acfc574616 Merge pull request 'amalia/19-agustus-25' (#14) from amalia/19-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#14
2025-08-19 17:43:28 +08:00
aef1c5ed84 upd: api mobile
Deskripsi:
- api mobile get list detail task project

No Issues
2025-08-19 17:40:25 +08:00
60215f49a5 upd: fitur baru task divisi
Deskripsi:
- api tambah detail detail task divisi
- api tambah task detail
- api edit task detail
- tampilan list detail task
- tampilan form tambah data task
- tampilan form tambah tugas detail task divisi
- tampilan form edit tugas detail task divisi

No Issues
2025-08-19 14:08:06 +08:00
bcbdc4c02b upd: fitur bary
Deskripsi:
- tambah data project detail jam task
- edit detail task jam pada fitur project
- api tambah data
- api edit data
- tampilan edit data
- tampilan tambah data

No Issues
2025-08-19 11:38:56 +08:00
4e64f041e9 Merge pull request 'upd: fitur baru' (#13) from amalia/18-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#13
2025-08-18 17:47:46 +08:00
3ec93ffe02 upd: fitur baru
Dekripsi:
- update struktur database
- tambah task detail jam pada project
- get list modal detail jam task project
- api get list detail jam task
- api tambah task detail jam pada project

No Issues
2025-08-18 17:46:28 +08:00
2bf919ac09 Merge pull request 'upd: api mobile' (#12) from amalia/15-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#12
2025-08-15 17:25:45 +08:00
7be78fad14 upd: api mobile
Deskripsi::
- api mobile laporan kegiatan project
- api mobile laporan kegiatan tugas divisi

No Issues
2025-08-15 13:59:57 +08:00
f3317a7190 Merge pull request 'amalia/14-agustus-25' (#11) from amalia/14-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#11
2025-08-14 17:14:23 +08:00
1f856ad3ab upd: laporan kegiatan
Deskripsi:
- update  struktur database
- api update laporan kegiatan project
- tampilan laporan kegiatan project
- form update laporan kegiatan project
- integrasi api update laporan kegiatan project
- api update laporan kegiatan tugas divisi
- tampilan laporan kegiatan tugas divisi
- form update laporan kegiatan tugas divisi
- integrasi api update laporan kegiatan tugas divisi

No Issues
2025-08-14 16:50:02 +08:00
2c98c2581d upd: tambah upload link
Deskripsi:
- api mobile tambah dan hapus link pada project
- api mobile tambah dan hapus link pada tugas divisi

No Issues
2025-08-14 12:15:33 +08:00
9df5a33386 Merge pull request 'upd: link upload' (#10) from amalia/13-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#10
2025-08-13 16:30:00 +08:00
b0dca49e04 upd: link upload
Deskripsi:
- update struktur db
- api tambah link pada projet
- api deelete link pada project
- api get link pada project
- api tambah link pada tugas divisi
- api delete link pada tugas divisi
- api get link pada tugas divisi
- tampilan modal tambah link pada project dan tugas divisi
- tampilan list link pada project dan tugas divisi
- tampilan modal detail link pada project dan tugas divisi

No Issues
2025-08-13 16:27:38 +08:00
09772910b7 Merge pull request 'upd: api mobile' (#9) from amalia/07-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#9
2025-08-07 17:41:01 +08:00
b075dae4b3 upd: api mobile
Deskripsi:
- update api diskusi umum dan diskusi divisi> pada post komentar fdm push notifikasi

No Issues
2025-08-07 17:37:13 +08:00
9b4dec8a39 Merge pull request 'join' (#8) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#8
2025-08-07 13:58:44 +08:00
494853db06 Merge pull request 'upd: api komen diskusi' (#7) from amalia/06-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#7
2025-08-06 17:33:48 +08:00
b625328789 upd: api komen diskusi
Deskripsi:
- update api mobile fcm komen diskusi

- update api version

No Issues
2025-08-06 14:28:29 +08:00
3561f80bf6 Merge pull request 'upd: api mobile' (#6) from amalia/06-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#6
2025-08-06 12:00:39 +08:00
c4d454ea58 upd: api mobile
Deskripsi:
- tambah fcm komentar diskusi umum

No ISsues
2025-08-06 11:57:12 +08:00
b4b6076693 Merge pull request 'join' (#5) from join into staging
Reviewed-on: bip/sistem-desa-mandiri#5
2025-08-04 14:17:16 +08:00
e766a6059d Merge pull request 'upd : api mobile' (#4) from amalia/04-agustus-25 into join
Reviewed-on: bip/sistem-desa-mandiri#4
2025-08-04 14:16:35 +08:00
7086a56e00 upd : api mobile
Deskripsi:
- api upload multiple file pada dokumen divisi

No ISsues
2025-08-04 14:11:47 +08:00
137 changed files with 9547 additions and 478 deletions

2573
darmasaba-api-ai.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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])
@@ -380,6 +420,7 @@ model DivisionDisscussionComment {
isActive Boolean @default(true)
User User @relation(fields: [createdBy], references: [id])
createdBy String
isEdited Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
@@ -575,6 +616,7 @@ model DiscussionComment {
idUser String
comment String @db.Text
isActive Boolean @default(true)
isEdited Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

View 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 &amp; 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 dependents 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>&copy; <span id="year"></span> Bali Interaktif Perkasa. All rights reserved.</p>
</footer>
</main>
<script>
document.getElementById('year').textContent = new Date().getFullYear();
</script>
</body>
</html>

View File

@@ -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>

View File

@@ -0,0 +1,8 @@
import { AddReportTask } from "@/module/task"
function Page() {
return (
<AddReportTask />
)
}
export default Page

View File

@@ -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>

View File

@@ -0,0 +1,9 @@
import { AddReportProject } from "@/module/project";
function Page() {
return (
<AddReportProject />
);
}
export default Page;

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 }
);
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View 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 });
}
}

View File

@@ -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
})

View File

@@ -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,
});

View File

@@ -3,8 +3,8 @@ import { funGetUserByCookies } from "@/module/auth";
import { createLogUser } from "@/module/user";
import _ from "lodash";
import moment from "moment";
import { NextResponse } from "next/server";
import "moment/locale/id";
import { NextResponse } from "next/server";
// GET ONE DETAIL DISKUSI UMUM
@@ -75,6 +75,9 @@ export async function GET(request: Request, context: { params: { id: string } })
img: true
}
}
},
orderBy: {
createdAt: "asc"
}
})

View File

@@ -74,6 +74,9 @@ export async function GET(request: Request) {
DiscussionComment: {
select: {
id: true,
},
where:{
isActive:true
}
}
}
@@ -147,7 +150,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 +176,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
})
}

View File

@@ -60,6 +60,12 @@ export async function GET(request: Request, context: { params: { id: string } })
img: true
}
}
},
where: {
isActive:true
},
orderBy: {
createdAt: "asc"
}
},
}

View File

@@ -64,6 +64,9 @@ export async function GET(request: Request) {
DivisionDisscussionComment: {
select: {
id: true,
},
where:{
isActive:true
}
}
}
@@ -146,6 +149,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 +162,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 +194,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 +226,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 +237,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
})

View File

@@ -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
})

View File

@@ -1,4 +1,3 @@
import { DivisionProject } from './../../../../node_modules/.prisma/client/index.d';
import { prisma } from "@/module/_global";
import { funGetUserByCookies } from "@/module/auth";
import _, { ceil } from "lodash";
@@ -36,22 +35,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,
@@ -74,7 +79,7 @@ export async function GET(request: Request) {
}
},
orderBy: {
createdAt: "desc"
updatedAt: "desc"
}
})
@@ -96,22 +101,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,
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,
@@ -134,7 +145,9 @@ export async function GET(request: Request) {
jumlah: v.DivisionProject.length,
}))
allData = _.orderBy(format, 'jumlah', 'desc').slice(0, 5)
const filter = format.filter((v: any) => v.jumlah > 0)
allData = _.orderBy(filter, 'jumlah', 'desc').slice(0, 5)
} else if (kategori == "progress") {
let kondisi
@@ -143,37 +156,50 @@ 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
}
}
// kondisi = {
// isActive: true,
// Division: {
// isActive: true,
// idVillage: idVillage,
// Group: {
// isActive: true,
// }
// }
// }
} else {
kondisi = {
isActive: true,
Division: {
isActive: true,
DivisionMember: {
some: {
idUser: user.id
}
}
}
idGroup: idGroup
}
}
// 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.divisionProject.groupBy({
const data = await prisma.project.groupBy({
where: kondisi,
by: ["status"],
_count: true
@@ -218,7 +244,7 @@ export async function GET(request: Request) {
}
}
}
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
} else {
kondisi = {
isActive: true,
category: 'FILE',
@@ -227,20 +253,30 @@ 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,
@@ -377,7 +413,7 @@ export async function GET(request: Request) {
}
}
}
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
} else {
kondisi = {
isActive: true,
status: 1,
@@ -386,20 +422,30 @@ 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
// }
// }
// }
// }
// }
const data = await prisma.divisionDisscussion.findMany({
skip: 0,

View File

@@ -20,6 +20,7 @@ export async function GET(request: Request, context: { params: { id: string } })
const data = await prisma.announcement.count({
where: {
id: id,
isActive: true,
},
});
@@ -29,7 +30,7 @@ export async function GET(request: Request, context: { params: { id: string } })
success: false,
message: "Gagal mendapatkan pengumuman, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}
@@ -173,7 +174,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
success: false,
message: "Edit pengumuman gagal, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}

View File

@@ -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,25 @@ export async function POST(request: Request) {
}
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
const dataNotifFilterUnique = dataNotifFilter
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t: any) => t.idUserTo == v.idUserTo)
)
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: dataNotifFilterUnique
})
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 }
})

View File

@@ -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 })

View File

@@ -11,7 +11,7 @@ export async function GET(request: Request) {
const userMobile = searchParams.get("user")
if (userMobile == "null" || userMobile == undefined || userMobile == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const user = await funGetUserById({ id: userMobile })

View File

@@ -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,108 @@ export async function POST(request: Request, context: { params: { id: string } }
}
})
const dataDiscussion = await prisma.discussion.findUnique({
where: {
id
},
select: {
createdBy: true,
User: {
select: {
Subscribe: {
select: {
subscription: true
}
},
TokenDeviceUser: {
select: {
token: true
}
}
}
}
}
})
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, { idUser: dataDiscussion?.createdBy, User: dataDiscussion?.User }].filter((v: any) => v.idUser != userMobile.id)
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t) => t.idUser === v.idUser)
);
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 });
@@ -43,4 +147,90 @@ export async function POST(request: Request, context: { params: { id: string } }
console.error(error)
return NextResponse.json({ success: false, message: "Gagal menambahkan komentar, coba lagi nanti (error: 500)" })
}
}
// EDIT KOMENTAR
export async function PUT(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params
const { desc, 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 cek = await prisma.discussionComment.count({
where: {
id,
isActive: true
}
})
if (cek == 0) {
return NextResponse.json({ success: false, message: "Gagal mengedit komentar, data tidak ditemukan" }, { status: 200 });
}
const data = await prisma.discussionComment.update({
where: {
id
},
data: {
comment: desc,
isEdited: true
}
})
// create log user
const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengedit komentar pada diskusi umum', table: 'discussionComment', data: id, user: userMobile.id })
return NextResponse.json({ success: true, message: "Berhasil mengedit komentar" }, { status: 200 });
} catch (error) {
console.error(error)
return NextResponse.json({ success: false, message: "Gagal mengedit komentar, coba lagi nanti (error: 500)" })
}
}
// HAPUS KOMENTAR
export async function DELETE(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params
const { 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 cek = await prisma.discussionComment.count({
where: {
id,
isActive: true
}
})
if (cek == 0) {
return NextResponse.json({ success: false, message: "Gagal mengedit komentar, data tidak ditemukan" }, { status: 200 });
}
const data = await prisma.discussionComment.update({
where: {
id
},
data: {
isActive: false
}
})
// create log user
const log = await createLogUserMobile({ act: 'DELETE', desc: 'User menghapus komentar pada diskusi umum', table: 'discussionComment', data: id, user: userMobile.id })
return NextResponse.json({ success: true, message: "Berhasil mengedit komentar" }, { status: 200 });
} catch (error) {
console.error(error)
return NextResponse.json({ success: false, message: "Gagal mengedit komentar, coba lagi nanti (error: 500)" })
}
}

View File

@@ -8,7 +8,7 @@ import { NextResponse } from "next/server";
// GET ONE DETAIL DISKUSI UMUM
export async function GET(request: Request, context: { params: { id: string } }) {
export async function GET(request : Request, context: { params: { id: string } }) {
try {
let dataFix
const { id } = context.params
@@ -19,7 +19,7 @@ export async function GET(request: Request, context: { params: { id: string } })
const user = await funGetUserById({ id: String(userMobile) })
if (user.id == "null" || user.id == undefined || user.id == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const cek = await prisma.discussion.count({
@@ -29,7 +29,7 @@ export async function GET(request: Request, context: { params: { id: string } })
})
if (cek == 0) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 404 });
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 200 });
}
if (kategori == "detail") {
@@ -68,6 +68,8 @@ export async function GET(request: Request, context: { params: { id: string } })
id: true,
comment: true,
createdAt: true,
updatedAt: true,
isEdited: true,
idUser: true,
User: {
select: {
@@ -75,12 +77,16 @@ export async function GET(request: Request, context: { params: { id: string } })
img: true
}
}
},
orderBy: {
createdAt: "asc"
}
})
dataFix = data.map((v: any) => ({
..._.omit(v, ["createdAt", "User",]),
..._.omit(v, ["createdAt", "User", "updatedAt"]),
createdAt: countTime(v.createdAt),
updatedAt: moment(v.updatedAt).format("ll"),
username: v.User.name,
img: v.User.img
}))

View File

@@ -15,7 +15,7 @@ export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const user = searchParams.get("user")
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const userMobile = await funGetUserById({ id: user })
@@ -75,6 +75,9 @@ export async function GET(request: Request) {
DiscussionComment: {
select: {
id: true,
},
where: {
isActive: true
}
}
}
@@ -172,7 +175,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 +208,25 @@ 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 dataNotifUnique = dataNotif
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t: any) => t.idUserTo == v.idUserTo)
)
const insertNotif = await prisma.notifications.createMany({
data: dataNotif
data: dataNotifUnique
})
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 }
})

View File

@@ -1,9 +1,11 @@
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
// CREATE COMENT
export async function POST(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params
@@ -38,10 +40,113 @@ 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,
createdBy: true,
User: {
select: {
Subscribe: {
select: {
subscription: true
}
},
TokenDeviceUser: {
select: {
token: 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, { idUser: dataDivision?.createdBy, User: dataDivision?.User }].filter((v: any) => v.idUser != userMobile.id)
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t) => t.idUser === v.idUser)
);
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 })
@@ -51,4 +156,103 @@ export async function POST(request: Request, context: { params: { id: string } }
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menambah komentar, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}
// EDIT KOMENTAR
export async function PUT(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params
const { comment, 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: "User tidak ditemukan" }, { status: 200 });
}
const cek = await prisma.divisionDisscussionComment.count({
where: {
id,
isActive: true
}
})
if (cek == 0) {
return NextResponse.json(
{
success: false,
message: "Edit komentar gagal, data tidak ditemukan",
},
{ status: 200 }
);
}
const data = await prisma.divisionDisscussionComment.update({
where: {
id: id
},
data: {
comment: comment,
isEdited: true
}
})
// create log user
const log = await createLogUserMobile({ act: 'UPDATE', desc: 'User mengedit komentar pada diskusi divisi', table: 'divisionDisscussionComment', data: id, user: userMobile.id })
return NextResponse.json({ success: true, message: "Berhasil mengedit komentar" }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menambah komentar, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}
// HAPUS KOMENTAR
export async function DELETE(request: Request, context: { params: { id: string } }) {
try {
const { id } = context.params
const { 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: "User tidak ditemukan" }, { status: 200 });
}
const cek = await prisma.divisionDisscussionComment.count({
where: {
id,
isActive: true
}
})
if (cek == 0) {
return NextResponse.json(
{
success: false,
message: "Hapus komentar gagal, data tidak ditemukan",
},
{ status: 200 }
);
}
const data = await prisma.divisionDisscussionComment.update({
where: {
id: id
},
data: {
isActive: false
}
})
// create log user
const log = await createLogUserMobile({ act: 'DELETE', desc: 'User menghapus komentar pada diskusi divisi', table: 'divisionDisscussionComment', data: id, user: userMobile.id })
return NextResponse.json({ success: true, message: "Berhasil menghapus komentar" }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menghapus komentar, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
}

View File

@@ -31,33 +31,42 @@ export async function GET(request: Request, context: { params: { id: string } })
success: false,
message: "Gagal mendapatkan diskusi, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}
if (cat == "comment") {
const data = await prisma.divisionDisscussionComment.findMany({
where: {
idDisscussion: id
idDisscussion: id,
isActive: true
},
select: {
id: true,
comment: true,
createdAt: true,
updatedAt: true,
isEdited: true,
createdBy: true,
User: {
select: {
name: true,
img: true
}
}
},
orderBy: {
createdAt: "asc"
}
})
const omitMember = data.map((v: any) => ({
..._.omit(v, ["User", "createdAt"]),
..._.omit(v, ["User", "createdBy", "createdAt", "updatedAt"]),
idUser: v.createdBy,
username: v.User.name,
img: v.User.img,
createdAt: countTime(v.createdAt),
updatedAt: moment(v.updatedAt).format("ll")
}))
return NextResponse.json({ success: true, message: "Berhasil mendapatkan komentar", data: omitMember }, { status: 200 });
@@ -128,7 +137,7 @@ export async function DELETE(request: Request, context: { params: { id: string }
});
if (data == 0) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 404 });
return NextResponse.json({ success: false, message: "Gagal mendapatkan diskusi, data tidak ditemukan" }, { status: 200 });
}
const result = await prisma.divisionDisscussion.update({

View File

@@ -35,7 +35,7 @@ export async function GET(request: Request) {
})
if (cekDivision == 0) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 404 });
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 200 });
}
const data = await prisma.divisionDisscussion.findMany({
@@ -67,6 +67,9 @@ export async function GET(request: Request) {
DivisionDisscussionComment: {
select: {
id: true,
},
where: {
isActive: true
}
}
}
@@ -118,7 +121,7 @@ export async function POST(request: Request) {
})
if (cekDivision == 0) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 404 });
return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, data tidak ditemukan" }, { status: 200 });
}
const data = await prisma.divisionDisscussion.create({
@@ -155,6 +158,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 +178,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 +217,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 +256,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 +265,25 @@ export async function POST(request: Request) {
})
}
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
const dataNotifFilterUnique = dataNotifFilter
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t: any) => t.idUserTo == v.idUserTo)
)
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: dataNotifFilterUnique
})
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 }
})

View File

@@ -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,24 @@ 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 dataNotifFilterUnique = dataNotifFilter
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t: any) => t.idUserTo == v.idUserTo)
)
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: dataNotifFilterUnique
})
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 }
})
@@ -337,4 +342,45 @@ export async function POST(request: Request) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menambahkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
};
// CEK DATA DIVISI (NAME DI DESA DAN GROUP YG SAMA)
export async function PUT(request: Request) {
try {
const sent = (await request.json())
const user = sent.user
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 fixGroup
if (sent.data.idGroup == "null" || sent.data.idGroup == undefined || sent.data.idGroup == "") {
fixGroup = userMobile.idGroup
} else {
fixGroup = sent.data.idGroup
}
const checkData = await prisma.division.count({
where: {
name: {
equals: sent.data.name,
mode: "insensitive"
},
idGroup: fixGroup,
idVillage: String(userMobile.idVillage)
}
})
if (checkData > 0) {
return NextResponse.json({ success: true, message: "Divisi dengan nama ini sudah ada", available: false }, { status: 200 });
}
return NextResponse.json({ success: true, message: "Berhasil cek data divisi", available: true }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ success: false, message: "Gagal menambahkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
}
};

View File

@@ -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 });

View File

@@ -12,7 +12,7 @@ export async function GET(request: Request, context: { params: { id: string } })
const userMobile = searchParams.get("user")
if (userMobile == "null" || userMobile == undefined || userMobile == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const { id } = context.params;
@@ -28,7 +28,7 @@ export async function GET(request: Request, context: { params: { id: string } })
success: false,
message: "Gagal mendapatkan grup, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}
@@ -52,7 +52,7 @@ export async function DELETE(request: Request, context: { params: { id: string }
const { isActive, user } = (await request.json());
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const userLogin = await funGetUserById({ id: user })
@@ -68,7 +68,7 @@ export async function DELETE(request: Request, context: { params: { id: string }
success: false,
message: "Edit grup gagal, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}
@@ -98,7 +98,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
const { name, user } = (await request.json());
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const data = await prisma.group.count({
@@ -113,7 +113,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
success: false,
message: "Edit grup gagal, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}

View File

@@ -11,7 +11,7 @@ export async function GET(request: Request) {
const userMobile = searchParams.get("user")
if (userMobile == "null" || userMobile == undefined || userMobile == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const user = await funGetUserById({ id: userMobile })
@@ -51,7 +51,7 @@ export async function POST(request: Request) {
const { name, user } = (await request.json());
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const userMobile = await funGetUserById({ id: user })

View File

@@ -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,
@@ -75,7 +81,7 @@ export async function GET(request: Request) {
}
},
orderBy: {
createdAt: "desc"
updatedAt: "desc"
}
})
@@ -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,10 +417,16 @@ 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") {
kondisiUmum = {
isActive: true,
status: 1,
idVillage: idVillage
}
kondisi = {
isActive: true,
status: 1,
@@ -388,7 +438,13 @@ export async function GET(request: Request) {
}
}
}
} else if (roleUser == "admin" || roleUser == "cosupadmin") {
} else {
kondisiUmum = {
isActive: true,
status: 1,
idGroup: idGroup,
}
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
})

View File

@@ -11,7 +11,7 @@ export async function GET(request: Request) {
const userMobile = searchParams.get("user")
if (userMobile == "null" || userMobile == undefined || userMobile == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const userId = await funGetUserById({ id: userMobile })

View File

@@ -11,7 +11,7 @@ export async function GET(request: Request, context: { params: { id: string } })
const { id } = context.params;
if (userMobile == "null" || userMobile == undefined || userMobile == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const data = await prisma.position.findUnique({
@@ -30,7 +30,7 @@ export async function GET(request: Request, context: { params: { id: string } })
success: false,
message: "Gagal mendapatkan jabatan, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}
@@ -55,7 +55,7 @@ export async function DELETE(request: Request, context: { params: { id: string }
const { isActive, user } = (await request.json());
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const data = await prisma.position.count({
@@ -104,12 +104,15 @@ export async function PUT(request: Request, context: { params: { id: string } })
const { name, idGroup, user } = await request.json();
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
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 }
);
}

View File

@@ -16,7 +16,7 @@ export async function GET(request: Request) {
const userMobile = searchParams.get("user")
if (userMobile == "null" || userMobile == undefined || userMobile == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const user = await funGetUserById({ id: userMobile })
@@ -35,7 +35,7 @@ export async function GET(request: Request) {
})
if (cek == 0) {
return NextResponse.json({ success: false, message: "Gagal mendapatkan jabatan, data tidak ditemukan", }, { status: 404 });
return NextResponse.json({ success: false, message: "Gagal mendapatkan jabatan, data tidak ditemukan", }, { status: 200 });
}
const filter = await prisma.group.findUnique({
@@ -61,6 +61,7 @@ export async function GET(request: Request) {
id: true,
name: true,
isActive: true,
idGroup: true,
Group: {
select: {
name: true
@@ -92,7 +93,7 @@ export async function POST(request: Request) {
const { name, idGroup, user } = await request.json();
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const userMobile = await funGetUserById({ id: user })
@@ -130,7 +131,7 @@ export async function POST(request: Request) {
} else {
return NextResponse.json(
{ success: false, message: "Jabatan sudah ada" },
{ status: 400 }
{ status: 200 }
);
}

View File

@@ -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 });
}
}

View 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 });
}
}

View File

@@ -71,7 +71,7 @@ export async function GET(request: Request, context: { params: { id: string } })
createdAt: true
},
orderBy: {
createdAt: 'asc'
dateStart: 'asc'
}
})
@@ -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 })

View File

@@ -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 })

View File

@@ -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: {

View File

@@ -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,23 @@ 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 dataNotifFilterUnique = dataNotifFilter
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t: any) => t.idUserTo == v.idUserTo)
)
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: dataNotifFilterUnique
})
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 }
})

View File

@@ -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 });
}
}

View 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 });
}
}

View File

@@ -76,7 +76,7 @@ export async function GET(request: Request, context: { params: { id: string } })
dateEnd: true,
},
orderBy: {
createdAt: 'asc'
dateStart: 'asc'
}
})
@@ -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: {

View File

@@ -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 })

View File

@@ -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: {

View File

@@ -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,24 @@ export async function POST(request: Request) {
})
}
const dataNotifFilter = dataNotif.filter((v: any) => v.idUserTo != undefined && v.idUserTo != null && v.idUserTo != "" && v.idUserTo != userId)
const dataNotifFilterUnique = dataNotifFilter
.filter((v: any, index: number, self: any[]) =>
index === self.findIndex((t: any) => t.idUserTo == v.idUserTo)
)
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: dataNotifFilterUnique
})
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

View File

@@ -87,7 +87,7 @@ export async function DELETE(request: Request, context: { params: { id: string }
const { isActive, user } = (await request.json());
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const data = await prisma.user.count({
@@ -102,7 +102,7 @@ export async function DELETE(request: Request, context: { params: { id: string }
success: false,
message: "Gagal mendapatkan anggota, data tidak ditemukan",
},
{ status: 404 }
{ status: 200 }
);
}
@@ -158,7 +158,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
} = JSON.parse(data as string)
if (user == "null" || user == undefined || user == "") {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const cekNIK = await prisma.user.count({
@@ -247,7 +247,7 @@ export async function PUT(request: Request, context: { params: { id: string } })
{ status: 200 }
);
} else {
return Response.json({ success: false, message: "Anggota sudah ada" }, { status: 400 });
return Response.json({ success: false, message: "Anggota sudah ada" }, { status: 200 });
}
} catch (error) {
console.error(error);

View File

@@ -11,7 +11,7 @@ export async function GET(request: Request) {
try {
const user = await funGetUserByCookies()
if (user.id == undefined) {
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 401 });
return NextResponse.json({ success: false, message: "Anda harus login untuk mengakses ini" }, { status: 200 });
}
const data = await prisma.user.findUnique({
where: {

View File

@@ -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) {

View File

@@ -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 });
}
}

View 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 });
}
}

View File

@@ -68,7 +68,7 @@ export async function GET(request: Request, context: { params: { id: string } })
createdAt: true
},
orderBy: {
createdAt: 'asc'
dateStart: 'asc'
}
})
@@ -78,8 +78,8 @@ export async function GET(request: Request, context: { params: { id: string } })
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
// const dataFix = _.orderBy(formatData, 'createdAt', 'asc')
allData = formatData
} else if (kategori == "file") {
const dataFile = await prisma.projectFile.findMany({
@@ -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) })

View File

@@ -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) })

View File

@@ -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
})

View File

@@ -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 });
}
}

View 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 });
}
}

View File

@@ -75,7 +75,7 @@ export async function GET(request: Request, context: { params: { id: string } })
dateEnd: true,
},
orderBy: {
createdAt: 'asc'
dateStart: 'asc'
}
})
@@ -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: {

View File

@@ -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 })

View File

@@ -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 })

View File

@@ -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.1.0", 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 });

View 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 &amp; 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 dependents 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>&copy; <span id="year"></span> Bali Interaktif Perkasa. All rights reserved.</p>
</footer>
</main>
</body>
</html>
`;

View 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
View File

@@ -0,0 +1,7 @@
export function urlCompleted(url: string) {
if (url.startsWith("http://") || url.startsWith("https://")) {
return url
} else {
return `https://${url}`
}
}

View File

@@ -18,7 +18,7 @@ export function countTime(date: Date) {
const seconds = totalSeconds;
if (days > 0) {
return moment(date).format("ll")
return String(dateNow.getFullYear()) == moment(date).format("YYYY") ? moment(date).format("DD MMM") : moment(date).format("ll")
} else if (hours > 0) {
return `${hours} jam`
} else if (minutes > 0) {

View File

@@ -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" }

View File

@@ -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",

View File

@@ -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)

View File

@@ -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>

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

Some files were not shown because too many files have changed in this diff Show More