diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/AppointmentController.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/AppointmentController.java index 28f307a50009563339c2768b29b2c5a2d9174d82..2a80edf512249bfcba598d5af0ed80427d507e20 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/AppointmentController.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/AppointmentController.java @@ -73,6 +73,14 @@ public class AppointmentController { @GetMapping("/appointment/view/{kode}") public String detailAppointment(@PathVariable("kode") String kode, Model model) { AppointmentModel appointment = appointmentService.findByKode(kode); + ResepModel resep = resepService.findResepModelByAppointment(appointment); + if (resep == null) { + // ada popup kalo tetep mau selesain tanpa resep + model.addAttribute("resep", false); + } + else { + model.addAttribute("resep", true); + } model.addAttribute("appointment", appointment); return "detail-appointment"; } @@ -83,25 +91,32 @@ public class AppointmentController { // cek apakah bisa di bikin done atau ga dulu ResepModel resep = resepService.findResepModelByAppointment(appointment); if (resep == null) { - // ada popup kalo tetep mau selesain tanpa resep - - } - else if (resep.getIsDone() == false) { - //gabisa selesai - - } - else { //jika berhasil is done - //buat tagihan TagihanModel tagihan = new TagihanModel(); tagihan.setTanggalTerbuat(LocalDateTime.now()); tagihan.setAppointment(appointment); tagihan.setIsPaid(false); tagihan.setJumlahTagihan(appointment.getDokter().getTarif()); tagihanService.addTagihan(tagihan); - //ganti status appointment + appointment.setIsDone(true); appointmentService.addAppointment(appointment); } +// else if (resep.getIsDone() == false) { +// //gabisa selesai jd ga ngapa2in +// +// } +// else { //jika berhasil is done +// //buat tagihan +// TagihanModel tagihan = new TagihanModel(); +// tagihan.setTanggalTerbuat(LocalDateTime.now()); +// tagihan.setAppointment(appointment); +// tagihan.setIsPaid(false); +// tagihan.setJumlahTagihan(appointment.getDokter().getTarif()); +// tagihanService.addTagihan(tagihan); +// //ganti status appointment +// appointment.setIsDone(true); +// appointmentService.addAppointment(appointment); +// } model.addAttribute("appointment", appointment); return "detail-appointment"; } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/DokterRestController.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/DokterRestController.java index e429a2b0c7622f122acc0da94f629619ef0ac4d2..830b40eab46580d91821ef716a95ebadf27aadb2 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/DokterRestController.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/DokterRestController.java @@ -2,6 +2,7 @@ package apap.tk.rumahSehat.controller.restController; import apap.tk.rumahSehat.model.AppointmentModel; import apap.tk.rumahSehat.model.DokterModel; +import apap.tk.rumahSehat.model.TagihanModel; import apap.tk.rumahSehat.model.UserModel; import apap.tk.rumahSehat.service.AppointmentServiceImpl; import apap.tk.rumahSehat.service.DokterServiceImpl; @@ -34,4 +35,10 @@ public class DokterRestController { private List<DokterModel> retrieveListDokter() { return dokterService.findAllDokter(); } + + @GetMapping(value = "/getPendapatan/{uuid0}/{uuid1}") + private List retrievePendapatan(@PathVariable("uuid0") String uuid0, @PathVariable("uuid1") String uuid1) { + return dokterService.getPendapatan(uuid0, uuid1); + } + } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/PasienRestController.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/PasienRestController.java index c17d0a36deb4de0e1cbebf87b3c67a0ecef43a58..1e99018a2e82b8882630023aff0047b8f39a7eb6 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/PasienRestController.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/PasienRestController.java @@ -13,6 +13,7 @@ import org.springframework.web.server.ResponseStatusException; import javax.validation.Valid; import java.util.List; import java.util.NoSuchElementException; +import java.util.Optional; @RestController @RequestMapping("/api/pasien") @@ -37,4 +38,20 @@ public class PasienRestController { private List<PasienModel> retrieveListPasien() { return pasienService.findAllPasien(); } + + @GetMapping(value = "/view/{username}") + private PasienModel retrieveCurrentPasien(@PathVariable("username") String username) { + return pasienService.findPasienByUsername(username); + } + + @PutMapping(value = "view/topup/{username}") + private PasienModel topUpSaldo(@PathVariable("username") String username, @RequestBody PasienModel pasien) { + try { + return pasienService.topUp(pasien); + } catch (NoSuchElementException e) { + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, "Code Course " + username + " not found" + ); + } + } } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/TagihanRestController.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/TagihanRestController.java index 8ca5ee6e8dd2aeea92a5b3728dc86df59fe7c0bb..b6a17f183866e2b760211f92d8e19989ddcc9cd7 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/TagihanRestController.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/controller/restController/TagihanRestController.java @@ -37,4 +37,15 @@ public class TagihanRestController { private List<TagihanModel> retrieveListTagihanOfPasien(@PathVariable("pasien") String pasien) { return tagihanService.findTagihanOfPasien(pasien); } + + @PutMapping(value = "/pay/{pasien}/{tagihan}") + private TagihanModel updateTagihan(@PathVariable("pasien") String pasien, @PathVariable("tagihan") String tagihan) { + return tagihanService.payTagihan(pasien, tagihan); + } + + /*@PostMapping(value = "/create/{tarif}/{appointment}") + private void makeTagihan(@PathVariable("tarif") Integer tarif, @PathVariable("appointment") String appointment) { + tagihanService.createTagihan(tarif, appointment); + + }*/ } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/model/PasienModel.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/model/PasienModel.java index 0e7e2b5d0dcc24fa1b8b580a9be511d04d01a79b..72bbbf7151709f58f2799bb2aa2b63773c78741d 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/model/PasienModel.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/model/PasienModel.java @@ -1,10 +1,13 @@ package apap.tk.rumahSehat.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import javax.persistence.*; import javax.validation.constraints.NotNull; @Entity @PrimaryKeyJoinColumn(name = "UUId") @Table(name = "Pasien") +@JsonIgnoreProperties({ "password"}) public class PasienModel extends UserModel{ @NotNull @Column(name ="saldo", nullable = false) diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/model/TagihanModel.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/model/TagihanModel.java index 6e835b3de531e01e66907943fd30cad6e293380d..885a058447ba98c08e254512a7754d83f5d2706d 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/model/TagihanModel.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/model/TagihanModel.java @@ -9,6 +9,7 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.lang.Nullable; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -39,8 +40,8 @@ public class TagihanModel { @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm") // Cek lagi private LocalDateTime tanggalTerbuat; - @NotNull - @Column(name = "tanggal_bayar", nullable = false) + @Nullable + @Column(name = "tanggal_bayar") @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm") // Cek lagi private LocalDateTime tanggalBayar; @@ -52,9 +53,6 @@ public class TagihanModel { @Column(name = "jumlah_tagihan", nullable = false) private Integer jumlahTagihan; -// @NotNull -// @Column(name = "kode_appointment", nullable = false) -// private String kodeAppointment; @OneToOne(fetch = FetchType.EAGER, optional = false) @JoinColumn(name = "kode_appointment", referencedColumnName = "kode", nullable = false) diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/DokterDb.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/DokterDb.java index 681a44ba17aeb2f4101ff3b96dbead92c8445f75..907658a7007e8f39db7bfad2f22a30bdef169944 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/DokterDb.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/DokterDb.java @@ -2,9 +2,20 @@ package apap.tk.rumahSehat.repository; import apap.tk.rumahSehat.model.DokterModel; import apap.tk.rumahSehat.model.ResepModel; +import apap.tk.rumahSehat.model.TagihanModel; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface DokterDb extends JpaRepository<DokterModel,String> { + @Query("SELECT dm.nama, SUM(dm.tarif)\n" + + "FROM DokterModel dm JOIN AppointmentModel am ON dm.UUId = am.dokter\n" + + "JOIN TagihanModel tm on tm.appointment.kode = am.kode\n" + + "WHERE (dm.UUId = :uuid0 OR dm.UUId = :uuid1) AND tm.isPaid = true\n" + + "GROUP BY dm") + List getPendapatan(@Param("uuid0") String uuid0, @Param("uuid1") String uuid1); } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/PasienDb.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/PasienDb.java index b4d029f698dc44c116639a5482fba88eecd2e91b..a37adf0ed1cc2aa16422984ff5f19d5ab82deff7 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/PasienDb.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/PasienDb.java @@ -5,7 +5,10 @@ import apap.tk.rumahSehat.model.PasienModel; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + + @Repository public interface PasienDb extends JpaRepository<PasienModel,String> { - + Optional<PasienModel> findByUsername(String username); } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/TagihanDb.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/TagihanDb.java index 0ebd790e9b31334715a0abfbe1b032b67a8985cc..4a0c25e2cb91e8f0062eb28623ca65616de46347 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/TagihanDb.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/repository/TagihanDb.java @@ -15,5 +15,7 @@ public interface TagihanDb extends JpaRepository<TagihanModel,String> { @Query("SELECT tm FROM TagihanModel tm JOIN AppointmentModel am ON tm.appointment.kode = am.kode WHERE am.pasien.UUId = :pasien") List<TagihanModel> findTagihanOfPasien(@Param("pasien") String pasien); - Optional<TagihanModel> findTagihanModelByAppointment(AppointmentModel appointment); + Optional<TagihanModel> findByKode (String kode ); + + Optional<TagihanModel> findByAppointment(AppointmentModel appointment); } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/security/WebSecurityConfig.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/security/WebSecurityConfig.java index 30eddd7f6a35e4c0c3cd28a9283485e0e39f99ac..2c4530026f767a56bb541c65f2e25b7d0dec4eb9 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/security/WebSecurityConfig.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/security/WebSecurityConfig.java @@ -20,17 +20,18 @@ public class WebSecurityConfig { http .csrf().disable() .authorizeRequests() - .antMatchers("/css/**").permitAll() - .antMatchers("/js/**").permitAll() + .antMatchers("/css/**").permitAll().antMatchers("/js/**").permitAll() .antMatchers("/api/**").permitAll() .antMatchers("/login-sso", "/validate-ticket").permitAll() .antMatchers("/create-dummy").permitAll() .antMatchers("/obat/viewall").hasAnyRole( "ADMIN", "APOTEKER") + .antMatchers("/appointment/viewall").not().hasRole("APOTEKER") .antMatchers("/obat/update").hasRole("APOTEKER") .antMatchers("/appointment/viewall").not().hasRole("APOTEKER") .antMatchers("/apoteker/**").hasRole("ADMIN") .antMatchers("/pasien/**").hasRole("ADMIN") .antMatchers("/dokter/**").hasRole("ADMIN") + .antMatchers("/api/pasien/add/**").permitAll() .anyRequest().authenticated() .and() .formLogin() diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/ApotekerServiceImpl.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/ApotekerServiceImpl.java index 71a6d434436199f9fb5b948bd823a2edceb34b24..dcf9f232afb87e573a54d8bf0c030520abcab70d 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/ApotekerServiceImpl.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/ApotekerServiceImpl.java @@ -1,9 +1,11 @@ package apap.tk.rumahSehat.service; import apap.tk.rumahSehat.model.ApotekerModel; +import apap.tk.rumahSehat.model.PasienModel; import apap.tk.rumahSehat.model.UserModel; import apap.tk.rumahSehat.repository.ApotekerDb; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -15,7 +17,12 @@ public class ApotekerServiceImpl { @Autowired ApotekerDb apotekerDb; + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } + public ApotekerModel addApoteker(ApotekerModel apoteker){ + apoteker.setPassword(encoder().encode(apoteker.getPassword())); apotekerDb.save(apoteker); return apoteker; } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/DokterServiceImpl.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/DokterServiceImpl.java index a28c873b1d73bb4ce068e32552b96cd57dc0b2cc..4f917fdcc3e4aee2c4859859e4d95c1392c0876b 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/DokterServiceImpl.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/DokterServiceImpl.java @@ -2,11 +2,13 @@ package apap.tk.rumahSehat.service; import apap.tk.rumahSehat.model.ApotekerModel; import apap.tk.rumahSehat.model.DokterModel; +import apap.tk.rumahSehat.model.PasienModel; import apap.tk.rumahSehat.repository.ApotekerDb; import apap.tk.rumahSehat.repository.DokterDb; import jdk.dynalink.linker.LinkerServices; import org.hibernate.tool.hbm2ddl.ForeignKeyMetadata; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -18,7 +20,12 @@ public class DokterServiceImpl { @Autowired DokterDb dokterDb; + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } + public DokterModel addDokter(DokterModel dokter){ + dokter.setPassword(encoder().encode(dokter.getPassword())); dokterDb.save(dokter); return dokter; } @@ -26,4 +33,8 @@ public class DokterServiceImpl { public List<DokterModel> findAllDokter(){ return dokterDb.findAll(); } + + public List getPendapatan(String uuid0, String uuid1) { + return dokterDb.getPendapatan(uuid0, uuid1); + } } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/PasienServiceImpl.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/PasienServiceImpl.java index a510457cfcd8d350a1eac6130f793fc7b5b0efe7..8bc9f9987473a119a8e34b9966426bd2c91b224c 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/PasienServiceImpl.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/PasienServiceImpl.java @@ -4,6 +4,7 @@ import apap.tk.rumahSehat.model.PasienModel; import apap.tk.rumahSehat.model.UserModel; import apap.tk.rumahSehat.repository.PasienDb; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -14,8 +15,12 @@ import java.util.List; public class PasienServiceImpl { @Autowired PasienDb pasienDb; + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } public PasienModel addPasien(PasienModel pasien){ + pasien.setPassword(encoder().encode(pasien.getPassword())); pasienDb.save(pasien); return pasien; } @@ -23,4 +28,12 @@ public class PasienServiceImpl { return pasienDb.findAll(); } + public PasienModel findPasienByUsername(String username){ + return pasienDb.findByUsername(username).get(); + } + + public PasienModel topUp(PasienModel pasien) { + pasienDb.save(pasien); + return pasien; + } } diff --git a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/TagihanServiceImpl.java b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/TagihanServiceImpl.java index 05606169877be5ac4b97ea1e2b9953939124ef92..8855100d0f49ce5cc58043dfd71bb11e1c7f3b0b 100644 --- a/rumahSehat/src/main/java/apap/tk/rumahSehat/service/TagihanServiceImpl.java +++ b/rumahSehat/src/main/java/apap/tk/rumahSehat/service/TagihanServiceImpl.java @@ -1,12 +1,16 @@ package apap.tk.rumahSehat.service; +import apap.tk.rumahSehat.model.PasienModel; import apap.tk.rumahSehat.model.AppointmentModel; import apap.tk.rumahSehat.model.TagihanModel; +import apap.tk.rumahSehat.repository.PasienDb; import apap.tk.rumahSehat.repository.TagihanDb; +import apap.tk.rumahSehat.repository.AppointmentDb; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -16,6 +20,12 @@ public class TagihanServiceImpl { @Autowired TagihanDb tagihanDb; + @Autowired + PasienDb pasienDb; + + @Autowired + AppointmentDb appointmentDb; + public TagihanModel addTagihan(TagihanModel tagihan){ tagihanDb.save(tagihan); return tagihan; @@ -30,8 +40,25 @@ public class TagihanServiceImpl { return tagihanOfPasien; } + public TagihanModel payTagihan (String pasien, String tagihan) { + PasienModel pasienModel = pasienDb.findByUsername(pasien).get(); + Integer saldo = pasienModel.getSaldo(); + TagihanModel tagihanModel = tagihanDb.findByKode(tagihan).get(); + Integer jumlahTagihan = tagihanModel.getJumlahTagihan(); + + if (saldo >= jumlahTagihan) { + pasienModel.setSaldo(saldo - jumlahTagihan); + pasienDb.save(pasienModel); + tagihanModel.setIsPaid(true); + tagihanModel.setTanggalBayar(LocalDateTime.now()); + return tagihanDb.save(tagihanModel); + } else { + return null; + } + } + public TagihanModel findTagihanByAppointment(AppointmentModel appointment) { - Optional<TagihanModel> tagihan = tagihanDb.findTagihanModelByAppointment(appointment); + Optional<TagihanModel> tagihan = tagihanDb.findByAppointment(appointment); if (tagihan.isPresent()) { return tagihan.get(); } diff --git a/rumahSehat/src/main/resources/templates/detail-appointment.html b/rumahSehat/src/main/resources/templates/detail-appointment.html index 775ad8162b42615543c8fde092ab0ac7800bff5c..d03db5933fbc9743912afda549c4137b012fbd60 100644 --- a/rumahSehat/src/main/resources/templates/detail-appointment.html +++ b/rumahSehat/src/main/resources/templates/detail-appointment.html @@ -69,8 +69,24 @@ <h5 class="table-title text-white ml-4 mt-2" th:text="${appointment.kode}"></h5> <div th:if="${appointment.isDone} == false"> <div sec:authorize="hasRole('DOKTER')"> - <a class="btn btn-warning" th:href="/">Create Resep</a> - <a class="btn btn-danger" th:href="@{/appointment/isDone/}+${appointment.kode}">is Done</a> + <div th:if="${resep} == false"> + <a class="btn btn-warning">Create Resep</a> + <a class="btn btn-danger" th:href="@{/appointment/isDone/}+${appointment.kode}" + th:confirmation="|Resep belum dibuat, apakah ingin diselesaikan?|" + onclick="if (!confirm(this.getAttribute('confirmation'))) return false" + >is Done</a> + </div> + <div th:unless="${resep} == false"> + <div th:if="${resep.isDone} == true"> + <a class="btn btn-danger" th:href="@{/appointment/isDone/}+${appointment.kode}">is Done</a> + </div> + <div th:unless="${resep.isDone} == true"> + <a class="btn btn-danger" th:href="@{/appointment/isDone/}+${appointment.kode}" + th:warning="|Resep belum terkonfirmasi, appointment tidak bisa diselesaikan|" + onclick="alert(this.getAttribute('warning'))" + >is Done</a> + </div> + </div> </div> </div> </div> diff --git a/rumahSehat_jwt/.gradle/7.5.1/checksums/checksums.lock b/rumahSehat_jwt/.gradle/7.5.1/checksums/checksums.lock index 2a1b58e42a88f432ee345a1117af3a41c3cdda3c..548a1a59b5de1fa2a252c23e432b36c2678df368 100644 Binary files a/rumahSehat_jwt/.gradle/7.5.1/checksums/checksums.lock and b/rumahSehat_jwt/.gradle/7.5.1/checksums/checksums.lock differ diff --git a/rumahSehat_jwt/.gradle/7.5.1/checksums/md5-checksums.bin b/rumahSehat_jwt/.gradle/7.5.1/checksums/md5-checksums.bin index 1e00ee030aee865ab0e61bb81df2fac72b4b9da1..9ba5bb25fee5a45d39a6d06f48885a310b31103d 100644 Binary files a/rumahSehat_jwt/.gradle/7.5.1/checksums/md5-checksums.bin and b/rumahSehat_jwt/.gradle/7.5.1/checksums/md5-checksums.bin differ diff --git a/rumahSehat_jwt/.gradle/7.5.1/checksums/sha1-checksums.bin b/rumahSehat_jwt/.gradle/7.5.1/checksums/sha1-checksums.bin index fc8165e50c43c4334fc0c167f3f630574fe571ed..d4a43e5dd45cc26416e964269d8c7046996aeaf4 100644 Binary files a/rumahSehat_jwt/.gradle/7.5.1/checksums/sha1-checksums.bin and b/rumahSehat_jwt/.gradle/7.5.1/checksums/sha1-checksums.bin differ diff --git a/rumahSehat_jwt/.gradle/7.5.1/executionHistory/executionHistory.lock b/rumahSehat_jwt/.gradle/7.5.1/executionHistory/executionHistory.lock index d0c7a10962110cda8eaa814a4493ff2235429611..addd217344e774031e2493af44285328c7e3f8d9 100644 Binary files a/rumahSehat_jwt/.gradle/7.5.1/executionHistory/executionHistory.lock and b/rumahSehat_jwt/.gradle/7.5.1/executionHistory/executionHistory.lock differ diff --git a/rumahSehat_jwt/.gradle/7.5.1/fileHashes/fileHashes.lock b/rumahSehat_jwt/.gradle/7.5.1/fileHashes/fileHashes.lock index d8858b264e5836b12a2c2f2b796d0c3f7f4f2cbe..ab5b775eddb76a8a60d8f0447782433771585029 100644 Binary files a/rumahSehat_jwt/.gradle/7.5.1/fileHashes/fileHashes.lock and b/rumahSehat_jwt/.gradle/7.5.1/fileHashes/fileHashes.lock differ diff --git a/rumahSehat_jwt/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/rumahSehat_jwt/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 12aedaba6946ebb1ee669f1153d12bf8ef684af8..d9e5b884802ab383dde28a8005b723609edce225 100644 Binary files a/rumahSehat_jwt/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/rumahSehat_jwt/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/ResepDb.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/ResepDb.class index e7c81a14970a9ab87bec29d821d40593b07da23f..5ccdb1bd77f10ad9d07c46fb70612e5fdbe8e817 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/ResepDb.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/ResepDb.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/TagihanDb.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/TagihanDb.class index cff83873695a48efd7a1e7f12ac90b9554b6e4ee..eeac6e48842e3fb2465fcc0e74d2ee35e410224f 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/TagihanDb.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/repository/TagihanDb.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/PasienRestController.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/PasienRestController.class index 75f25e7674dd0e013c8266429be5031a438d00dc..21b0050177e85764a6235a1f68e9ea2267af1748 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/PasienRestController.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/PasienRestController.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/ResepRestController.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/ResepRestController.class index 7c36038050d6c88049cb20ffd979a6841c6cc744..d9a7200e33e8f5542bd0c4c3bf01fc1a9353b742 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/ResepRestController.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/ResepRestController.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/TagihanRestController.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/TagihanRestController.class index c8792edb412cf1eaba37d9ec518f0fcfcf7e866d..d75575484b070214b8510ff6f03c47b74342a400 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/TagihanRestController.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/restController/TagihanRestController.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.class index f9871454015db28042b1d6b0a860d80893346989..302086cb3611487fef60512a7a1b89cedca32472 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.class index 5cec2869e5d987fcaec319ab061cb13f77e30e23..ea8d11e9c58737a2a8685cd08239667985b1563a 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.class index 86cb48e5ec349e6e466a1f1086e936028bb9f866..2e87fc6cbabde2b0d1b14aadf1268ffa3a3bb7e3 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.class index 3bc9bfcb58a9b697d96632a000eccbe500e58b0f..846b0842962b41a900ca0d86278176ec22f14c5f 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.class index 457459ea33a11aa72f3ef39974ab48aa91eb3cd4..a2e7c1e95cb35135fc8822e479a3a7058f4c8853 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.class index e85b5194669c553b9a2d34fb9ecde3280dc883bf..5559be856770ef8a9892de6d870e31b271a59cc3 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.class differ diff --git a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.class b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.class index 724fa13e6d02bcc1600ebb2dd23b027e2cd9bc9e..0d368d2e5baf6ceae9d84406706183751ce30981 100644 Binary files a/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.class and b/rumahSehat_jwt/bin/main/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.class differ diff --git a/rumahSehat_jwt/local.properties b/rumahSehat_jwt/local.properties index 1ec7bab827403fc89aae8f80548534b8350e0ebb..d852b958f66721cac1ee897b600234e4994c4dde 100644 --- a/rumahSehat_jwt/local.properties +++ b/rumahSehat_jwt/local.properties @@ -4,5 +4,10 @@ # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Fri Nov 25 17:07:26 WIB 2022 -sdk.dir=/Users/davidjohan/Library/Android/sdk +<<<<<<< HEAD +#Wed Nov 30 09:26:09 WIB 2022 +sdk.dir=C\:\\Users\\farel\\AppData\\Local\\Android\\Sdk +======= +#Tue Dec 06 12:40:14 WIB 2022 +sdk.dir=C\:\\Users\\muham\\AppData\\Local\\Android\\Sdk +>>>>>>> 228646434f6ccbedf90e2ae3bc075765875c277f diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/ResepDb.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/ResepDb.java index 16492068aa87bd2a455e21e06218b48fea8f15ed..cc691507c6723611992c1b1a66f68950775e9fd5 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/ResepDb.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/ResepDb.java @@ -1,10 +1,14 @@ package apap.tk.rumahSehat_jwt.repository; +import apap.tk.rumahSehat_jwt.model.AppointmentModel; import apap.tk.rumahSehat_jwt.model.ResepModel; import apap.tk.rumahSehat_jwt.model.TagihanModel; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface ResepDb extends JpaRepository<ResepModel,String> { + Optional<ResepModel> findByAppointment(AppointmentModel appointmen); } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/TagihanDb.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/TagihanDb.java index 61bf538002b87c40829a44b63188adddff41806d..dcad743f6dae67632a42f6c02e3e3bbcf560a472 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/TagihanDb.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/repository/TagihanDb.java @@ -1,9 +1,19 @@ package apap.tk.rumahSehat_jwt.repository; +import apap.tk.rumahSehat_jwt.model.PasienModel; import apap.tk.rumahSehat_jwt.model.TagihanModel; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface TagihanDb extends JpaRepository<TagihanModel,String> { + @Query("SELECT tm FROM TagihanModel tm JOIN AppointmentModel am ON tm.appointment.kode = am.kode WHERE am.pasien.username = :pasien") + List<TagihanModel> findTagihanOfPasien(@Param("pasien") String pasien); + + Optional<TagihanModel> findByKode (String kode ); } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/PasienRestController.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/PasienRestController.java index 2b5cd650f6d484c398348e0e0833feff4f1fe955..dd5957b83e14db8840136c27ef8861686c94fbf5 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/PasienRestController.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/PasienRestController.java @@ -13,6 +13,7 @@ import org.springframework.web.server.ResponseStatusException; import javax.validation.Valid; import java.util.List; import java.util.NoSuchElementException; +import java.util.Optional; @RestController @RequestMapping("/api/pasien") @@ -37,4 +38,20 @@ public class PasienRestController { private List<PasienModel> retrieveListPasien() { return pasienService.findAllPasien(); } + + @GetMapping(value = "/view/{username}") + private PasienModel retrieveCurrentPasien(@PathVariable("username") String username) { + return pasienService.findPasienByUsername(username); + } + + @PutMapping(value = "view/topup/{username}") + private PasienModel topUpSaldo(@PathVariable("username") String username, @RequestBody PasienModel pasien) { + try { + return pasienService.topUp(pasien); + } catch (NoSuchElementException e) { + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, "Pasien dengan username: " + username + " tidak ditemukan" + ); + } + } } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/ResepRestController.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/ResepRestController.java index 3e10845280eb5ae8e9486c9bcff26e64f35374a9..3acc077eeaf1f34af3cea6babbdee21a7003049f 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/ResepRestController.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/ResepRestController.java @@ -1,14 +1,13 @@ package apap.tk.rumahSehat_jwt.restController; +import apap.tk.rumahSehat_jwt.model.AppointmentModel; import apap.tk.rumahSehat_jwt.model.ResepModel; +import apap.tk.rumahSehat_jwt.service.AppointmentServiceImpl; import apap.tk.rumahSehat_jwt.service.ResepServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; import javax.validation.Valid; @@ -19,6 +18,9 @@ public class ResepRestController { @Autowired private ResepServiceImpl resepService; + @Autowired + private AppointmentServiceImpl appointmentService; + @PostMapping(value = "/add") private ResepModel createResep(@Valid @RequestBody ResepModel resep, BindingResult bindingResult) { if (bindingResult.hasFieldErrors()) { @@ -28,4 +30,11 @@ public class ResepRestController { return resepService.addResep(resep); } } + + @GetMapping(value = "/view/{kodeApt}") + private ResepModel retrieveAppointment(@PathVariable("kodeApt") String kodeApt) { + AppointmentModel appointment = appointmentService.findByKode(kodeApt); + ResepModel resep = resepService.findByAppointment(appointment); + return resep; + } } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/TagihanRestController.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/TagihanRestController.java index a7e869373e9cd7243d1bf523f6f36f12fbe7568c..857a017e4e801f20ab28d16aeb39f8b9438b351a 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/TagihanRestController.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/restController/TagihanRestController.java @@ -32,4 +32,14 @@ public class TagihanRestController { private List<TagihanModel> retrieveListTagihan() { return tagihanService.findAllTagihan(); } + + @GetMapping(value = "/viewAll/{pasien}") + private List<TagihanModel> retrieveListTagihanOfPasien(@PathVariable("pasien") String pasien) { + return tagihanService.findTagihanOfPasien(pasien); + } + + @PutMapping(value = "/pay/{pasien}/{tagihan}") + private TagihanModel updateTagihan(@PathVariable("pasien") String pasien, @PathVariable String tagihan) { + return tagihanService.payTagihan(pasien, tagihan); + } } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.java index 107fad0961e0391bb2e2ee5586637dba2e70dfbc..0ee56ac152ecd4f205d80ae8f6d119007c634256 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/security/WebSecurityConfig.java @@ -57,7 +57,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { http.cors().and().csrf().disable() .exceptionHandling().authenticationEntryPoint((AuthenticationEntryPoint) unauthorizedHandler).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .authorizeRequests().antMatchers("/api/auth/**").permitAll() + .authorizeRequests().antMatchers("/api/auth/**","/api/pasien/add/**").permitAll() .anyRequest().authenticated(); http.addFilterBefore((Filter) authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.java index df7a9bc4cbdf09bd353b40327936169db61daaca..1d5b603e3b416f1f970148f113eb6551ee127e53 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ApotekerServiceImpl.java @@ -1,9 +1,11 @@ package apap.tk.rumahSehat_jwt.service; import apap.tk.rumahSehat_jwt.model.ApotekerModel; +import apap.tk.rumahSehat_jwt.model.PasienModel; import apap.tk.rumahSehat_jwt.model.UserModel; import apap.tk.rumahSehat_jwt.repository.ApotekerDb; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -14,8 +16,11 @@ import java.util.List; public class ApotekerServiceImpl { @Autowired ApotekerDb apotekerDb; - + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } public ApotekerModel addApoteker(ApotekerModel apoteker){ + apoteker.setPassword(encoder().encode(apoteker.getPassword())); apotekerDb.save(apoteker); return apoteker; } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.java index 1d47ef830b332fd70e46b83878bdac2c4b19aaf2..0c3bb0d8862069c7300342b47f6beaa967985f1c 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/AppointmentServiceImpl.java @@ -25,6 +25,9 @@ public class AppointmentServiceImpl { List<AppointmentModel> allAppointment = findAllAppointment(); LocalDateTime waktuAwalBaru = appointment.getWaktuAwal(); LocalDateTime waktuAkhirBaru = waktuAwalBaru.plusHours(1); + if (waktuAwalBaru.isBefore(LocalDateTime.now())) { + return null; + } for (int i = 0; i < allAppointment.size(); i++) { AppointmentModel currentAppointment = allAppointment.get(i); LocalDateTime waktuAwal = currentAppointment.getWaktuAwal(); diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.java index 0ffc9ab8aed8dfe4d0a668fa6ce00151141d6f6a..b67eb976e92d535c207de4f4957e006379731a61 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/DokterServiceImpl.java @@ -2,11 +2,13 @@ package apap.tk.rumahSehat_jwt.service; import apap.tk.rumahSehat_jwt.model.ApotekerModel; import apap.tk.rumahSehat_jwt.model.DokterModel; +import apap.tk.rumahSehat_jwt.model.PasienModel; import apap.tk.rumahSehat_jwt.repository.ApotekerDb; import apap.tk.rumahSehat_jwt.repository.DokterDb; import jdk.dynalink.linker.LinkerServices; import org.hibernate.tool.hbm2ddl.ForeignKeyMetadata; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -18,7 +20,11 @@ public class DokterServiceImpl { @Autowired DokterDb dokterDb; + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } public DokterModel addDokter(DokterModel dokter){ + dokter.setPassword(encoder().encode(dokter.getPassword())); dokterDb.save(dokter); return dokter; } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.java index db06d34a0c6f80c83abaa50b973c45f3b71f34f9..e279da17e4b8927502f9b7ebcb2022f7efa19b00 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/PasienServiceImpl.java @@ -4,6 +4,7 @@ import apap.tk.rumahSehat_jwt.model.PasienModel; import apap.tk.rumahSehat_jwt.model.UserModel; import apap.tk.rumahSehat_jwt.repository.PasienDb; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -14,8 +15,12 @@ import java.util.List; public class PasienServiceImpl { @Autowired PasienDb pasienDb; + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } public PasienModel addPasien(PasienModel pasien){ + pasien.setPassword(encoder().encode(pasien.getPassword())); pasienDb.save(pasien); return pasien; } @@ -27,4 +32,8 @@ public class PasienServiceImpl { return pasienDb.findByUsername(username).get(); } + public PasienModel topUp(PasienModel pasien) { + pasienDb.save(pasien); + return pasien; + } } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.java index ae63209243d05b27a81dea937e3bb148ae66e07d..26cd6d140296b860a137054a122c1b56c8a613ad 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/ResepServiceImpl.java @@ -1,11 +1,13 @@ package apap.tk.rumahSehat_jwt.service; +import apap.tk.rumahSehat_jwt.model.AppointmentModel; import apap.tk.rumahSehat_jwt.model.ResepModel; import apap.tk.rumahSehat_jwt.repository.ResepDb; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.util.Optional; @Service @Transactional @@ -17,4 +19,14 @@ public class ResepServiceImpl { resepDb.save(resep); return resep; } + + public ResepModel findByAppointment(AppointmentModel appointment){ + Optional<ResepModel> resep = resepDb.findByAppointment(appointment); + if (resep.isPresent()) { + return resep.get(); + } + else { + return null; + } + } } diff --git a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.java b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.java index 5774df1952e5e6212203f94c9d307e9bd6d97595..48c016249fc54a5c1b98cb358e8b284ecbd0a289 100644 --- a/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.java +++ b/rumahSehat_jwt/src/main/java/apap/tk/rumahSehat_jwt/service/TagihanServiceImpl.java @@ -1,7 +1,9 @@ package apap.tk.rumahSehat_jwt.service; +import apap.tk.rumahSehat_jwt.model.PasienModel; import apap.tk.rumahSehat_jwt.model.TagihanModel; import apap.tk.rumahSehat_jwt.repository.TagihanDb; +import apap.tk.rumahSehat_jwt.repository.PasienDb; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -14,6 +16,9 @@ public class TagihanServiceImpl { @Autowired TagihanDb tagihanDb; + @Autowired + PasienDb pasienDb; + public TagihanModel addTagihan(TagihanModel tagihan){ tagihanDb.save(tagihan); return tagihan; @@ -22,4 +27,26 @@ public class TagihanServiceImpl { public List<TagihanModel> findAllTagihan(){ return tagihanDb.findAll(); } + + public List<TagihanModel> findTagihanOfPasien(String pasien) { + List<TagihanModel> tagihanOfPasien = tagihanDb.findTagihanOfPasien(pasien); + return tagihanOfPasien; + } + + public TagihanModel payTagihan (String pasien, String tagihan) { + PasienModel pasienModel = pasienDb.findByUsername(pasien).get(); + Integer saldo = pasienModel.getSaldo(); + TagihanModel tagihanModel = tagihanDb.findByKode(tagihan).get(); + Integer jumlahTagihan = tagihanModel.getJumlahTagihan(); + + if (saldo >= jumlahTagihan) { + pasienModel.setSaldo(saldo - jumlahTagihan); + pasienDb.save(pasienModel); + tagihanModel.setIsPaid(true); + return tagihanDb.save(tagihanModel); + } else { + return tagihanModel; + } + + } } diff --git a/rumahSehat_mobile/android/local.properties b/rumahSehat_mobile/android/local.properties index 264303e9b0b90fcf945505a2cc66626634d432ca..4c7f6b127d412e031b80fd9989253bcee7a44693 100644 --- a/rumahSehat_mobile/android/local.properties +++ b/rumahSehat_mobile/android/local.properties @@ -1,6 +1,12 @@ -sdk.dir=/Users/davidjohan/Library/Android/sdk +<<<<<<< HEAD +sdk.dir=C:\\Users\\farel\\AppData\\Local\\Android\\sdk ======= -flutter.sdk=/Users/davidjohan/Developer/flutter +flutter.sdk=C:\\Users\\farel\\Documents\\flutter +======= +sdk.dir=C:\\Users\\muham\\AppData\\Local\\Android\\sdk +======= +flutter.sdk=C:\\flutter +>>>>>>> 228646434f6ccbedf90e2ae3bc075765875c277f flutter.buildMode=debug flutter.versionName=1.0.0 flutter.versionCode=1 \ No newline at end of file diff --git a/rumahSehat_mobile/lib/appointment/AppointmentModel.dart b/rumahSehat_mobile/lib/appointment/AppointmentModel.dart index beefc4fdd41cc795b076c4178af02dbd915115c2..0f81e0e1f8459524cdeab7e354786f68263edaaf 100644 --- a/rumahSehat_mobile/lib/appointment/AppointmentModel.dart +++ b/rumahSehat_mobile/lib/appointment/AppointmentModel.dart @@ -4,21 +4,31 @@ class AppointmentModel { final String namaPasien; final String waktuAwal; final bool isDone; - final String? tagihan; + final bool punyaResep; const AppointmentModel({ required this.kode, required this.namaDokter, required this.namaPasien, required this.waktuAwal, - required this.tagihan, + required this.punyaResep, required this.isDone, }); - factory AppointmentModel.fromJson(Map<String, dynamic> json) { + factory AppointmentModel.fromJson(Map<String?, dynamic> json) { + if (json['listResep'].isEmpty) { + return AppointmentModel( + kode: json['kode'], + punyaResep: false, + namaPasien: json['pasien']['nama'], + namaDokter: json['dokter']['nama'], + waktuAwal: json['waktuAwal'], + isDone: json['isDone'], + ); + } return AppointmentModel( kode: json['kode'], - tagihan: json['tagihan'], + punyaResep: true, namaPasien: json['pasien']['nama'], namaDokter: json['dokter']['nama'], waktuAwal: json['waktuAwal'], diff --git a/rumahSehat_mobile/lib/appointment/create_appointment_dev.dart b/rumahSehat_mobile/lib/appointment/create_appointment_dev.dart index 9f81e9b817f3fa4014ab9cf68d1cb437deb8d0a7..7e2482ec1d2488c2e2aefc472527e0d42e5ae622 100644 --- a/rumahSehat_mobile/lib/appointment/create_appointment_dev.dart +++ b/rumahSehat_mobile/lib/appointment/create_appointment_dev.dart @@ -7,6 +7,7 @@ import 'package:http/http.dart' as http; import 'dart:async'; import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:rumahsehat_mobile/appointment/view_all_appointment.dart'; class FormAppointmentDev extends StatefulWidget { const FormAppointmentDev({Key? key}) : super(key: key); @@ -40,13 +41,6 @@ class FormAppointmentDevState extends State<FormAppointmentDev> { setState(() { dataDokter = resBody; }); - // print(dataDokter); - // print(dataDokter.map((item) { - // return DropdownMenuItem( - // child: Text(item['nama']), - // value: item['id'].toString(), - // ); - // }).toList()[0].toString()); return "Sucess"; } @@ -163,7 +157,7 @@ class FormAppointmentDevState extends State<FormAppointmentDev> { ), sizedBox, Text( - "Nama Dokter", + "Pilihan Dokter", style: Theme.of(context).textTheme.subtitle1!.copyWith( color: kTextBlackColor, fontSize: SizerUtil.deviceType == DeviceType.tablet @@ -198,7 +192,7 @@ class FormAppointmentDevState extends State<FormAppointmentDev> { sizedBox, OutlinedButton( style: OutlinedButton.styleFrom( - side: BorderSide(color: Colors.green, width: 1), //<-- SEE HERE + side: BorderSide(color: Colors.green, width: 1), ), child: Text( "Submit", @@ -212,21 +206,25 @@ class FormAppointmentDevState extends State<FormAppointmentDev> { formKey.currentState!.save(); bool response = await createAppointment(valDokter, dateTime); if (response == true) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Pembuatan Appointment Berhasil')), - ); + Navigator.pushNamed( + context, ViewAllAppointment.routeName); + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar(content: Text('Pembuatan Appointment Berhasil')), //masukin ke detail appointment + // ); } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Pembuatan Appointment Gagal')), - ); + showAlertDialog(context); + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar(content: Text('Pembuatan Appointment Gagal')), + // ); } - print(response.toString()); + // print(response.toString()); } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Pembuatan Appointment Gagal')), - ); + showAlertDialog(context); + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar(content: Text('Pembuatan Appointment Gagal')), + // ); } }, ), @@ -237,5 +235,29 @@ class FormAppointmentDevState extends State<FormAppointmentDev> { ), ); } +} + +showAlertDialog(BuildContext context) { + // Create button + Widget okButton = TextButton( + child: const Text("Ok"), + onPressed: () { + Navigator.of(context).pop(); + }, + ); + AlertDialog alert = AlertDialog( + backgroundColor: kOtherColor, + title: const Text("Create Appointment Failed!"), + actions: [ + okButton, + ], + ); + + showDialog( + context: context, + builder: (BuildContext context) { + return alert; + }, + ); } \ No newline at end of file diff --git a/rumahSehat_mobile/lib/appointment/detail_appointment.dart b/rumahSehat_mobile/lib/appointment/detail_appointment.dart index b0bd048c21d78555d0467f84de5d66c3e0845260..ceba2f8af189584ef3425061d1c043329847a340 100644 --- a/rumahSehat_mobile/lib/appointment/detail_appointment.dart +++ b/rumahSehat_mobile/lib/appointment/detail_appointment.dart @@ -30,36 +30,69 @@ class DetailAppointment extends StatefulWidget { class DetailAppointmentState extends State<DetailAppointment> { final String urlAppointment = get_appointment_url; + final String urlResep = get_resep_url; Future<AppointmentModel> getAppointmentData() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? _jwtToken = prefs.getString('jwtToken'); // String? _username = prefs.getString('username'); - print(_jwtToken); - // print(_username); var res = await http.get(Uri.parse(urlAppointment + "/$widget.kodeApt"), - // var res = await http.get(Uri.parse(urlAppointment), headers: <String, String>{ 'Content-Type' : 'application/json;charset=UTF-8', 'Authorization' : 'Bearer $_jwtToken', - // 'Connection': 'keep-alive' }); if (res.statusCode == 200) { final Map<String, dynamic> jsonResponse = json.decode(res.body); - print(jsonResponse); final appointment = AppointmentModel.fromJson(jsonResponse); - print(appointment); return appointment; - // return jsonResponse.map((data) => new AppointmentModel.fromJson(data)); } else { throw Exception('Appointment gagal ditampilkan'); } } + Future<bool> getResepStatus() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String kode = widget.appointment.kode; + // String? _username = prefs.getString('username'); + var res = await http.get(Uri.parse(urlResep + "/$kode"), + headers: <String, String>{ + 'Content-Type' : 'application/json;charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken', + }); + if (res.statusCode == 200) { + final Map<String, dynamic> jsonResponse = json.decode(res.body); + if (jsonResponse == null) { + // return false; + return Future<bool>.value(false); + } + else { + // return true; + return Future<bool>.value(true); + } + // final appointment = AppointmentModel.fromJson(jsonResponse); + } + else { + throw Exception('Resep gagal diperoleh'); + } + } + + // Future<Widget> showwidget() async { + // bool response = await getResepStatus(); + // if (response == true) { + // return Text("Y is greater than or equal to 10"); + // }else{ + // return Text("Y is less than 10"); + // } + // } + @override void initState() { super.initState(); + if (getResepStatus() == false) { + print("Tidak ada resep"); + } } @override @@ -87,13 +120,6 @@ class DetailAppointmentState extends State<DetailAppointment> { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - CircleAvatar( - radius: - SizerUtil.deviceType == DeviceType.tablet ? 12.w : 13.w, - backgroundColor: kOtherColor, - backgroundImage: - AssetImage('assets/images/avatar-male.png'), - ), kWidthSizedBox, Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -125,10 +151,22 @@ class DetailAppointmentState extends State<DetailAppointment> { title: "Waktu Appointment", value: convertTanggal(widget.appointment.waktuAwal), ), - DetailColumn( - title: "Tagihan", - value: getTagihan(widget.appointment.tagihan), + sizedBox, + if (widget.appointment.punyaResep) ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => DetailAppointment(appointment: widget.appointment)), + ); + } , + child: Text ( + 'Detail Resep' + ), ), + // DetailColumn( + // title: "Tagihan", + // value: getTagihan(widget.appointment.tagihan), + // ), ], ), ), @@ -164,12 +202,6 @@ class DetailColumn extends StatelessWidget { ), kHalfSizedBox, Text(value, - // style: Theme.of(context).textTheme.subtitle1!.copyWith( - // color: kTextBlackColor, - // fontSize: SizerUtil.deviceType == DeviceType.tablet - // ? 20.sp - // : 15.sp, - // ), style: Theme.of(context).textTheme.labelLarge, ), kHalfSizedBox, @@ -196,14 +228,14 @@ String getStatus(bool isDone) { } } -String getTagihan(String? tagihan) { - if (tagihan == null) { - return 'Tidak ada'; - - } else { - return tagihan.toString(); - } -} +// String getTagihan(String? tagihan) { +// if (tagihan == null) { +// return 'Tidak ada'; +// +// } else { +// return tagihan.toString(); +// } +// } String convertTanggal(String waktuAwal) { DateTime converted = new DateFormat("yyyy-MM-ddThh:mm:ss").parse(waktuAwal); diff --git a/rumahSehat_mobile/lib/appointment/view_all_appointment.dart b/rumahSehat_mobile/lib/appointment/view_all_appointment.dart index 3dd9532cdea40cfe3662778d3d5c066b8d3a0f12..d2beba64fa1d207deb0d7c69ab09a914c52de837 100644 --- a/rumahSehat_mobile/lib/appointment/view_all_appointment.dart +++ b/rumahSehat_mobile/lib/appointment/view_all_appointment.dart @@ -183,13 +183,15 @@ class AppointmentFieldRow extends StatelessWidget { children: [ Text( field, - style: Theme.of(context).textTheme.caption!.copyWith( + style: Theme.of(context).textTheme.subtitle1!.copyWith( color: kTextBlackColor, + fontSize: SizerUtil.deviceType == DeviceType.tablet + ? 18.sp + : 12.sp, ), ), - Text(value, style: Theme.of(context).textTheme.subtitle2!.copyWith( - color: kTextBlackColor, - )), + Text(value, style: Theme.of(context).textTheme.labelLarge, + ), ], ); } diff --git a/rumahSehat_mobile/lib/home_page/home.dart b/rumahSehat_mobile/lib/home_page/home.dart index 7788164f38f5fc98858758488ef46f7bd18a43c4..152d94d58a2e5f6a83690f80295592e399fb8592 100644 --- a/rumahSehat_mobile/lib/home_page/home.dart +++ b/rumahSehat_mobile/lib/home_page/home.dart @@ -6,12 +6,56 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:rumahsehat_mobile/appointment/create_appointment_dev.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:rumahsehat_mobile/user_page/PasienModel.dart'; +import 'package:http/http.dart' as http; +import 'package:rumahsehat_mobile/url_settings.dart'; +import 'dart:convert'; //Home Screen -class HomeScreen extends StatelessWidget { +class HomeScreen extends StatefulWidget { const HomeScreen({Key? key}) : super(key: key); static String routeName = 'HomeScreen'; + + @override + HomeScreenState createState() => HomeScreenState(); +} + +class HomeScreenState extends State<HomeScreen> { + final String urlProfile = get_pasien_url; + late Future<PasienModel> futurePasienData; + + final Future<SharedPreferences> _prefs = SharedPreferences.getInstance(); + late Future<String> _username; + late Future<String> _jwtToken; + + Future<PasienModel> getUserData() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String? _username = prefs.getString('username'); + var res = await http + .get(Uri.parse(urlProfile + "/$_username"), + headers: <String, String>{ + 'Content-Type' : 'application/json;charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken' + } + ); + return PasienModel.fromJson(jsonDecode(res.body)); + } + + @override + void initState() { + super.initState(); + _username = _prefs.then((SharedPreferences prefs) { + return prefs.getString('username') ?? ''; + }); + _jwtToken = _prefs.then((SharedPreferences prefs) { + return prefs.getString('jwtToken') ?? ''; + }); + futurePasienData = getUserData(); + } + @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; @@ -21,97 +65,115 @@ class HomeScreen extends StatelessWidget { centerTitle: true, leading: IconButton(icon: Icon(Icons.menu), onPressed: () {},), ), - body: Container( - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.only( - topRight: Radius.circular(30), topLeft: Radius.circular(30))), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - margin: EdgeInsets.only(top: 20, left: 20), - child: Text( - "Hi, User!", - style: GoogleFonts.poppins( - color: kTextBlackColor, - fontSize: 16, - fontWeight: FontWeight.w500 - ), - ), - ), Container( - margin: EdgeInsets.only(top: 5, left: 20), - child: Text( - "Welcome Back", - style: GoogleFonts.poppins( - color: kTextBlackColor, - fontSize: 20, - fontWeight: FontWeight.w700, - ), - ), - ), - Container( - width: size.width, - margin: EdgeInsets.only(top: 20, left: 20), - child: Stack( - fit: StackFit.loose, - children: [ - Container( - child: Text( - 'Category', - style: GoogleFonts.poppins( - color: kTextBlackColor, - fontSize: 14, - ), - ), - ), - ], - ), - ), - Container( - height: 120, - margin: EdgeInsets.only(top: 10, left: 20), - child: ListView( - scrollDirection: Axis.horizontal, - children: [ - HomeCard( - onPress: () { - Navigator.pushNamed( - context, UserProfileScreen.routeName); - }, - icon: "assets/icons/ui_user_profile.svg", - title: "My Profile" - ), - HomeCard( - onPress: () { - Navigator.pushNamed( - context, FormAppointmentDev.routeName); - }, - icon: "assets/icons/add.svg", - title: "New Appointment" + body: FutureBuilder<PasienModel>( + future: futurePasienData, + builder: (context, AsyncSnapshot<PasienModel> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return const Center( + child: CircularProgressIndicator(), + ); + default: + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Container( + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.only( + topRight: Radius.circular(30), topLeft: Radius.circular(30))), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(top: 20, left: 20), + child: Text( + "Hi, " + snapshot.data!.nama +"!", + style: GoogleFonts.poppins( + color: kTextBlackColor, + fontSize: 16, + fontWeight: FontWeight.w500 + ), + ), + ), + Container( + margin: EdgeInsets.only(top: 5, left: 20), + child: Text( + "Welcome Back", + style: GoogleFonts.poppins( + color: kTextBlackColor, + fontSize: 20, + fontWeight: FontWeight.w700, + ), + ), + ), + Container( + width: size.width, + margin: EdgeInsets.only(top: 20, left: 20), + child: Stack( + fit: StackFit.loose, + children: [ + Container( + child: Text( + 'Category', + style: GoogleFonts.poppins( + color: kTextBlackColor, + fontSize: 14, + ), + ), + ), + ], + ), + ), + Container( + height: 120, + margin: EdgeInsets.only(top: 10, left: 20), + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + HomeCard( + onPress: () { + Navigator.pushNamed( + context, UserProfileScreen.routeName); + }, + icon: "assets/icons/ui_user_profile.svg", + title: "My Profile" + ), + HomeCard( + onPress: () { + Navigator.pushNamed( + context, FormAppointmentDev.routeName); + }, + icon: "assets/icons/add.svg", + title: "New Appointment" + ), + HomeCard( + onPress: () { + Navigator.pushNamed( + context, ViewAllAppointment.routeName); + }, + icon: "assets/icons/appointment.svg", + title: "My Appointment" + ), + HomeCard( + onPress: () { + Navigator.pushNamed( + context, ViewAllTagihanScreen.routeName); + }, + icon: "assets/icons/bills.svg", + title: "My Tagihan" + ) + ], + ), + ), + ] ), - HomeCard( - onPress: () { - Navigator.pushNamed( - context, ViewAllAppointment.routeName); - }, - icon: "assets/icons/appointment.svg", - title: "My Appointment" - ), - HomeCard( - onPress: () { - Navigator.pushNamed( - context, ViewAllTagihanScreen.routeName); - }, - icon: "assets/icons/bills.svg", - title: "My Tagihan" - ) - ], - ), - ), - ]), - ), + ); + } + } + } + ) ); } } diff --git a/rumahSehat_mobile/lib/login.dart b/rumahSehat_mobile/lib/login.dart index 8ba8a156a3dab685838d2bd7ca8c469a3e0d65c7..75f032a8d433fe8020362d6dd882c7608f594c7b 100644 --- a/rumahSehat_mobile/lib/login.dart +++ b/rumahSehat_mobile/lib/login.dart @@ -16,7 +16,7 @@ class LoginFormState extends State<LoginForm> { final TextEditingController _pass = TextEditingController(); final Future<SharedPreferences> _prefs = SharedPreferences.getInstance(); - late String _name; + late String _nama; late String _password; late Future<String> _email; late Future<String> _username; @@ -104,7 +104,7 @@ class LoginFormState extends State<LoginForm> { child: Container( padding: const EdgeInsets.only(top: 120, left: 24, right: 24), child: Center( - child: Column( + child: Column( children: [ const Padding(padding: EdgeInsets.only(top: 40.0)), const Text( @@ -193,11 +193,12 @@ class LoginFormState extends State<LoginForm> { 'username':username, 'password':password })); - if (response1.statusCode == 200 ) { + if (response1.statusCode == 200) { final Map parsed = json.decode(response1.body); _loginUser(parsed['name'],parsed['email'],parsed['jwtToken']); setState((){ print("success"); + print(username); _success=true; _message="Berhasil Masuk"; }); diff --git a/rumahSehat_mobile/lib/main.dart b/rumahSehat_mobile/lib/main.dart index 4191aaca2eb96435ec8ad532625fde285c29d481..2480cd45de212f593f0dd688ec2b0bab5930d7fe 100644 --- a/rumahSehat_mobile/lib/main.dart +++ b/rumahSehat_mobile/lib/main.dart @@ -25,8 +25,8 @@ class MyApp extends StatelessWidget { theme: CustomTheme().baseTheme, //initial route is splash screen //mean first screen - // initialRoute: LoginPage.routeName, // Uncomment ini kalo mau pake UI Login dari Hilmy - home: LoginForm(), + home: LoginPage(), // Uncomment ini kalo mau pake UI Login dari Hilmy + // home: LoginForm(), // home: HomeScreen(), // home: DetailAppointment(), //define the routes file here in order to access the routes any where all over the app diff --git a/rumahSehat_mobile/lib/register_page/login_page.dart b/rumahSehat_mobile/lib/register_page/login_page.dart index dd3313e58687ab17044de88ad21d3b39c623dafd..482cda09373bdb4ac62a59a4326ce7236c96f221 100644 --- a/rumahSehat_mobile/lib/register_page/login_page.dart +++ b/rumahSehat_mobile/lib/register_page/login_page.dart @@ -6,8 +6,13 @@ import 'package:rumahsehat_mobile/fragments.dart'; import 'package:rumahsehat_mobile/home_page/home.dart'; import 'package:rumahsehat_mobile/register_page/common/theme_helper.dart'; +import 'package:http/http.dart' as http; +import 'package:rumahsehat_mobile/url_settings.dart'; +import 'dart:convert'; +import 'package:quickalert/quickalert.dart'; import 'regist_page.dart'; import 'widgets/header_widget.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class LoginPage extends StatefulWidget{ static String routeName = 'LoginPage'; @@ -17,10 +22,56 @@ class LoginPage extends StatefulWidget{ } class _LoginPageState extends State<LoginPage>{ + final Future<SharedPreferences> _prefs = SharedPreferences.getInstance(); + + late String _password; + late Future<String> _email; + late Future<String> _username; + late Future<String> _jwtToken; + late String _message; + late bool _success; + + @override + void initState() { + super.initState(); + setState(() { + _message = ""; + _success = false; + }); + } + + Future<void> _loginUser( + String username, String email, String jwtToken) async { + final SharedPreferences prefs = await _prefs; + setState(() { + _email = prefs.setString('email', email).then((bool success) { + return email; + }); + _username = prefs.setString('username', username).then((bool success) { + return username; + }); + _jwtToken = prefs.setString("jwtToken", jwtToken).then((value) { + return jwtToken; + }); + }); + } + double _headerHeight = 300; final _formKey = GlobalKey<FormState>(); - String _username = ""; - String _password = ""; + + bool hidepassword = true; + TextEditingController usernameCont = TextEditingController(); + TextEditingController passwordCont = TextEditingController(); + + String username = ""; + String password = ""; + bool ada = false; + + void togglePasswordView() { + setState(() { + hidepassword = !hidepassword; + }); + } @override Widget build(BuildContext context) { @@ -38,7 +89,7 @@ class _LoginPageState extends State<LoginPage>{ ), Container( padding: EdgeInsets.fromLTRB(20, 0, 20, 10), - margin: EdgeInsets.fromLTRB(20, 0, 20, 10),// This will be the login form + margin: EdgeInsets.fromLTRB(20, 0, 20, 10),// This will be the login form child: Column( children: [ SizedBox(height: 10.0), @@ -53,19 +104,20 @@ class _LoginPageState extends State<LoginPage>{ ), SizedBox(height: 10.0), Form( - key: _formKey, + key: _formKey, child: Column( children: [ Container( child: TextFormField( style: TextStyle(color: Colors.black, fontWeight: FontWeight.w400, fontSize: 16), decoration: ThemeHelper().textInputDecoration('Username', 'Enter your Username'), + controller: usernameCont, + autovalidateMode: AutovalidateMode.onUserInteraction, validator: (uname) { if (uname!.isEmpty) { return 'Username Tidak boleh kosong'; } - _username = uname; - print(uname); + username = uname; return null; }, ), @@ -74,15 +126,39 @@ class _LoginPageState extends State<LoginPage>{ SizedBox(height: 15.0), Container( child: TextFormField( - obscureText: true, + obscureText: hidepassword, style: TextStyle(color: Colors.black, fontWeight: FontWeight.w400, fontSize: 16), - decoration: ThemeHelper().textInputDecoration('Password', 'Enter your password'), - validator: (password) { - if (password!.isEmpty) { + decoration: + InputDecoration( + hintStyle: TextStyle(color: Colors.grey.shade400, fontSize: 14), + labelText: 'Password', + hintText: 'Enter your password', + fillColor: Colors.white, + filled: true, + contentPadding: EdgeInsets.fromLTRB(20, 10, 20, 10), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.grey),), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.grey.shade400)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.red, width: 2.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.red, width: 2.0)), + suffixIcon: IconButton( + color: const Color.fromRGBO(200, 200, 200, 1), + splashRadius: 1, + icon: Icon(hidepassword + ? Icons.visibility_off_outlined + : Icons.visibility_outlined), + onPressed: togglePasswordView, + ), + ), + controller: passwordCont, + onChanged: (String value) { + password = value; + }, + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: (pass) { + if (pass!.isEmpty) { return 'Password Tidak boleh kosong'; } - _password = password; - print(password); + password = pass; return null; }, ), @@ -93,36 +169,76 @@ class _LoginPageState extends State<LoginPage>{ Container( decoration: ThemeHelper().buttonBoxDecoration(context), child: ElevatedButton( - style: ThemeHelper().buttonStyle(), - child: Padding( - padding: EdgeInsets.fromLTRB(40, 10, 40, 10), - child: Text('LOGIN'.toUpperCase(), style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white),), - ), - onPressed: (){ - if (_formKey.currentState!.validate()) { - Navigator.pushNamed( - context, HomeScreen.routeName); + style: ThemeHelper().buttonStyle(), + child: Padding( + padding: EdgeInsets.fromLTRB(40, 10, 40, 10), + child: Text('LOGIN'.toUpperCase(), style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white),), + ), + onPressed: () async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + print("uname: " + username +" - pass:"+ password); + final response1 = await http.post(Uri.parse( + auth_login), + headers: <String, String>{ + 'Content-Type': 'application/json;charset=UTF-8' + }, + body: jsonEncode(<String,String>{ + 'username':username, + 'password':password + })); + print(response1.statusCode); + if (response1.statusCode == 200 ) { + final Map parsed = json.decode(response1.body); + _loginUser(parsed['name'],parsed['email'],parsed['jwtToken']); + setState((){ + print("success"); + _success=true; + _message="Berhasil Masuk"; + }); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + HomeScreen())); + } else { + QuickAlert.show( + context: context, + type: QuickAlertType.error, + title: 'Login Failed', + text: 'Please check again your username and password ', + ); + // showAlertDialog(context, username); + } + } else { + QuickAlert.show( + context: context, + type: QuickAlertType.error, + title: 'Login Failed', + text: 'Please check again your username and password ', + ); + // showAlertDialog(context, username); + } } - }, ), ), Container( margin: EdgeInsets.fromLTRB(10,20,10,20), //child: Text('Don\'t have an account? Create'), child: Text.rich( - TextSpan( - children: [ - TextSpan(text: "Don\'t have an account? ",style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w200)), - TextSpan( - text: 'Sign up', - recognizer: TapGestureRecognizer() - ..onTap = (){ - Navigator.push(context, MaterialPageRoute(builder: (context) => RegistPage())); - }, - style: TextStyle(fontWeight: FontWeight.normal, color: Theme.of(context).accentColor, fontSize: 16), - ), - ] - ) + TextSpan( + children: [ + TextSpan(text: "Don\'t have an account? ",style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w200)), + TextSpan( + text: 'Sign up', + recognizer: TapGestureRecognizer() + ..onTap = (){ + Navigator.push(context, MaterialPageRoute(builder: (context) => RegistPage())); + }, + style: TextStyle(fontWeight: FontWeight.normal, color: Theme.of(context).accentColor, fontSize: 16), + ), + ] + ) ), ), ], @@ -130,7 +246,7 @@ class _LoginPageState extends State<LoginPage>{ ), ], ) - ), + ), ], ), ), diff --git a/rumahSehat_mobile/lib/register_page/regist_page.dart b/rumahSehat_mobile/lib/register_page/regist_page.dart index a353f33d07614482177c780c357a0518d13baa08..cb602464c22e2be6f40a35d29e4acb437cb7ab92 100644 --- a/rumahSehat_mobile/lib/register_page/regist_page.dart +++ b/rumahSehat_mobile/lib/register_page/regist_page.dart @@ -5,6 +5,7 @@ import 'package:http/http.dart' as http; import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:quickalert/quickalert.dart'; import 'package:rumahsehat_mobile/fragments.dart'; import 'package:rumahsehat_mobile/home_page/home.dart'; import 'package:rumahsehat_mobile/register_page/common/theme_helper.dart'; @@ -29,6 +30,14 @@ class _RegistPageState extends State<RegistPage>{ String _username = ""; String _password = ""; + bool hidepassword = true; + + void togglePasswordView() { + setState(() { + hidepassword = !hidepassword; + }); + } + @override Widget build(BuildContext context) { final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); @@ -45,7 +54,7 @@ class _RegistPageState extends State<RegistPage>{ ), Container( padding: EdgeInsets.fromLTRB(20, 0, 20, 10), - margin: EdgeInsets.fromLTRB(20, 0, 20, 10),// This will be the login form + margin: EdgeInsets.fromLTRB(20, 0, 20, 10),// This will be the login form child: Column( children: [ SizedBox(height: 10.0), @@ -60,7 +69,7 @@ class _RegistPageState extends State<RegistPage>{ ), SizedBox(height: 10.0), Form( - key: _formKey, + key: _formKey, child: Column( children: [ Container( @@ -72,7 +81,6 @@ class _RegistPageState extends State<RegistPage>{ return 'Nama Tidak boleh kosong'; } _nama = name; - print(_nama); return null; }, ), @@ -89,7 +97,6 @@ class _RegistPageState extends State<RegistPage>{ return 'Umur Tidak boleh kosong'; } _umur = int.parse(umur); - print(_umur); return null; }, ), @@ -110,7 +117,6 @@ class _RegistPageState extends State<RegistPage>{ return 'Email Tidak Valid'; } _email = email; - print(_email); return null; }, ), @@ -126,7 +132,6 @@ class _RegistPageState extends State<RegistPage>{ return 'Username Tidak boleh kosong'; } _username = uname; - print(_username); return null; }, ), @@ -135,15 +140,33 @@ class _RegistPageState extends State<RegistPage>{ SizedBox(height: 15.0), Container( child: TextFormField( - obscureText: true, + obscureText: hidepassword, style: TextStyle(color: Colors.black, fontWeight: FontWeight.w400, fontSize: 16), - decoration: ThemeHelper().textInputDecoration('Password', 'Enter your password'), + decoration: InputDecoration( + hintStyle: TextStyle(color: Colors.grey.shade400, fontSize: 14), + labelText: 'Password', + hintText: 'Enter your password', + fillColor: Colors.white, + filled: true, + contentPadding: EdgeInsets.fromLTRB(20, 10, 20, 10), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.grey),), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.grey.shade400)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.red, width: 2.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0), borderSide: BorderSide(color: Colors.red, width: 2.0)), + suffixIcon: IconButton( + color: const Color.fromRGBO(200, 200, 200, 1), + splashRadius: 1, + icon: Icon(hidepassword + ? Icons.visibility_off_outlined + : Icons.visibility_outlined), + onPressed: togglePasswordView, + ), + ), validator: (password) { if (password!.isEmpty) { return 'Password Tidak boleh kosong'; } _password = password; - print(_password); return null; }, ), @@ -162,8 +185,15 @@ class _RegistPageState extends State<RegistPage>{ onPressed: () async { if (_formKey.currentState!.validate()) { if(await createPasien(_nama, _username, _password, _email, _umur)){ - Navigator.pushNamed( - context, HomeScreen.routeName); + QuickAlert.show( + context: context, + type: QuickAlertType.success, + title: 'Account has Been Created!', + text: 'Please login', + confirmBtnText: "Login", + onConfirmBtnTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage())), + barrierDismissible: false, + ); } } }, @@ -173,19 +203,19 @@ class _RegistPageState extends State<RegistPage>{ margin: EdgeInsets.fromLTRB(10,20,10,20), //child: Text('Don\'t have an account? Create'), child: Text.rich( - TextSpan( - children: [ - TextSpan(text: "Already have an account? ",style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w200)), - TextSpan( - text: 'Login', - recognizer: TapGestureRecognizer() - ..onTap = (){ - Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage())); - }, - style: TextStyle(fontWeight: FontWeight.normal, color: Theme.of(context).accentColor, fontSize: 16), - ), - ] - ) + TextSpan( + children: [ + TextSpan(text: "Already have an account? ",style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w200)), + TextSpan( + text: 'Login', + recognizer: TapGestureRecognizer() + ..onTap = (){ + Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage())); + }, + style: TextStyle(fontWeight: FontWeight.normal, color: Theme.of(context).accentColor, fontSize: 16), + ), + ] + ) ), ), ], @@ -193,7 +223,7 @@ class _RegistPageState extends State<RegistPage>{ ), ], ) - ), + ), ], ), ), @@ -201,6 +231,21 @@ class _RegistPageState extends State<RegistPage>{ } } +Future<bool> checkUsername(String uname) async { + String url = "/uname_verif?username=$uname"; + try { + var response = await http.get(Uri.parse(url)); + Map<String, dynamic> extractedData = jsonDecode(response.body); + if (extractedData["availability"] == true) { + return true; + } + return false; + } catch (error) { + print("Username Checker Error"); + return false; + } +} + Future<bool> createPasien(String nama, String username, String password, String email, int umur) async { final response = await http.post( diff --git a/rumahSehat_mobile/lib/tagihan/pay_tagihan_result.dart b/rumahSehat_mobile/lib/tagihan/pay_tagihan_result.dart new file mode 100644 index 0000000000000000000000000000000000000000..80eba63c4607ac1eecc55a40dd637400e5ba63fb --- /dev/null +++ b/rumahSehat_mobile/lib/tagihan/pay_tagihan_result.dart @@ -0,0 +1,183 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:rumahsehat_mobile/url_settings.dart'; +import 'package:sizer/sizer.dart'; +import 'package:rumahsehat_mobile/fragments.dart'; +import 'package:rumahsehat_mobile/home_page/home.dart'; +import 'package:rumahsehat_mobile/tagihan/TagihanModel.dart'; +import 'package:rumahsehat_mobile/tagihan/view_detail_tagihan.dart'; +import 'dart:async'; + +import 'package:http/http.dart' as http; + +import 'package:flutter/cupertino.dart'; + +import 'package:shared_preferences/shared_preferences.dart'; + +class PayTagihanResultScreen extends StatefulWidget { + const PayTagihanResultScreen({Key? key, required this.tagihanToPay}) : super(key: key); + static String routeName = "PayTagihanResultScreen"; + final TagihanModel tagihanToPay; + + @override + _PayTagihanResultScreenState createState() => _PayTagihanResultScreenState(); +} + +class _PayTagihanResultScreenState extends State<PayTagihanResultScreen> { + late Future<TagihanModel> futureTagihan; + + @override + void initState() { + super.initState(); + futureTagihan = payTagihan(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Hasil Bayar Tagihan"), + centerTitle: true, + leading: IconButton(icon: Icon(Icons.arrow_back_ios), onPressed: () + { + Navigator.pushNamed( + context, HomeScreen.routeName); + },), + ), + body: Column( + children: [ + Expanded(child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(kDefaultPadding), + topRight: Radius.circular(kDefaultPadding), + ), + color: kOtherColor + ), + child: + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FutureBuilder<TagihanModel> ( + future: futureTagihan, + builder: (context, snapshot){ + if(snapshot.hasData) { + TagihanModel? tagihanProcessed = snapshot.data; + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (tagihanProcessed!.isPaid) ...[ + Text('Tagihan ' + tagihanProcessed!.kode + " telah dibayar.", + style: Theme.of(context).textTheme.caption!.copyWith( + color: kTextBlackColor, + ), + ), + sizedBox, + Text('Saldo Anda berkurang sebanyak ' + tagihanProcessed!.jumlahTagihan.toString(), + style: Theme.of(context).textTheme.caption!.copyWith( + color: kTextBlackColor, + ), + ), + sizedBox, + ElevatedButton( + onPressed: () { + Navigator.pushNamed( + context, HomeScreen.routeName); + }, + child: Text("Kembali ke Home")) + ] else ...[ + Text('Tagihan ' + tagihanProcessed!.kode + " gagal dibayar.", + style: Theme.of(context).textTheme.caption!.copyWith( + color: kTextBlackColor, + ), + ), + sizedBox, + Text('Saldo Anda tidak mencukupi, silakan top up terlebih dahulu.', + style: Theme.of(context).textTheme.caption!.copyWith( + color: kTextBlackColor, + ), + ), + sizedBox, + ElevatedButton( + onPressed: () { + Navigator.pushNamed( + context, HomeScreen.routeName); + }, + child: Text("Kembali ke Home")) + ] + ], + ); + + } else if (snapshot.hasError) { + return Text("${snapshot.error}"); + } + // By default show a loading spinner. + return CircularProgressIndicator(); + }, + ), + ], + ), + + )), + ], + ), + + ); + } + + Future<TagihanModel> payTagihan() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String? _username = prefs.getString('username'); + print(_jwtToken); + print(_username); + var response = await http.put(Uri.parse(pay_tagihan + "/$_username" + "/" + widget.tagihanToPay.kode), + // var res = await http.get(Uri.parse(urlAppointment), + headers: <String, String>{ + 'Content-Type' : 'application/json;charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken', + // 'Connection': 'keep-alive' + }); + + //final response = await http.get(Uri.parse('https://5e20b8d6-3e15-4f5f-b02d-301f98f72aa2.mock.pstmn.io/api/tagihan/viewAll')); + if (response.statusCode == 200) { + // If the server did return a 200 OK response, + // then parse the JSON. + return TagihanModel.fromJson(json.decode(response.body)); + } else { + // If the server did not return a 200 OK response, + // then throw an exception. + throw Exception('Gagal membayar tagihan'); + } + } +} + + + + + +class TagihanFieldRow extends StatelessWidget { + const TagihanFieldRow({Key? key, required this.field, required this.value}) + : super(key: key); + final String field; + final String value; + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + field, + style: Theme.of(context).textTheme.caption!.copyWith( + color: kTextBlackColor, + ), + ), + Text(value, style: Theme.of(context).textTheme.subtitle2!.copyWith( + color: kTextBlackColor + )), + ], + ); + } +} \ No newline at end of file diff --git a/rumahSehat_mobile/lib/tagihan/view_all_tagihan.dart b/rumahSehat_mobile/lib/tagihan/view_all_tagihan.dart index a7639e638119c4428d20e8f2af5ccab9f1874ca2..0e977d2ed01538c03d9ead5759e90a183d149ed5 100644 --- a/rumahSehat_mobile/lib/tagihan/view_all_tagihan.dart +++ b/rumahSehat_mobile/lib/tagihan/view_all_tagihan.dart @@ -1,13 +1,17 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:rumahsehat_mobile/url_settings.dart'; import 'package:sizer/sizer.dart'; import 'package:rumahsehat_mobile/fragments.dart'; import 'package:rumahsehat_mobile/home_page/home.dart'; import 'package:rumahsehat_mobile/tagihan/TagihanModel.dart'; +import 'package:rumahsehat_mobile/tagihan/view_detail_tagihan.dart'; import 'dart:async'; import 'package:http/http.dart' as http; import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + class ViewAllTagihanScreen extends StatefulWidget { const ViewAllTagihanScreen({Key? key}) : super(key: key); static String routeName = "ViewAllTagihanScreen"; @@ -91,8 +95,12 @@ class _ViewAllTagihanState extends State<ViewAllTagihanScreen> { sizedBox, ElevatedButton( onPressed: () { - Navigator.pushNamed( - context, HomeScreen.routeName); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TagihanDetailScreen(tagihanToView: tagihanList[index]) + ), + ); } , child: Text ( 'Detail' @@ -121,7 +129,20 @@ class _ViewAllTagihanState extends State<ViewAllTagihanScreen> { } Future<List<TagihanModel>> fetchTagihan() async { - final response = await http.get(Uri.parse('https://5e20b8d6-3e15-4f5f-b02d-301f98f72aa2.mock.pstmn.io/api/tagihan/viewAll')); + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String? _username = prefs.getString('username'); + print(_jwtToken); + print(_username); + var response = await http.get(Uri.parse(get_all_tagihan_url + "/$_username"), + // var res = await http.get(Uri.parse(urlAppointment), + headers: <String, String>{ + 'Content-Type' : 'application/json;charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken', + // 'Connection': 'keep-alive' + }); + + //final response = await http.get(Uri.parse('https://5e20b8d6-3e15-4f5f-b02d-301f98f72aa2.mock.pstmn.io/api/tagihan/viewAll')); if (response.statusCode == 200) { // If the server did return a 200 OK response, // then parse the JSON. diff --git a/rumahSehat_mobile/lib/tagihan/view_detail_tagihan.dart b/rumahSehat_mobile/lib/tagihan/view_detail_tagihan.dart new file mode 100644 index 0000000000000000000000000000000000000000..751d4290f2fc357f4077d3ea3241d3d8f31a0501 --- /dev/null +++ b/rumahSehat_mobile/lib/tagihan/view_detail_tagihan.dart @@ -0,0 +1,152 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:rumahsehat_mobile/tagihan/pay_tagihan_result.dart'; +import 'package:rumahsehat_mobile/url_settings.dart'; +import 'package:sizer/sizer.dart'; +import 'package:rumahsehat_mobile/fragments.dart'; +import 'package:rumahsehat_mobile/home_page/home.dart'; +import 'package:rumahsehat_mobile/tagihan/TagihanModel.dart'; +import 'package:rumahsehat_mobile/tagihan/view_all_tagihan.dart'; +import 'dart:async'; + +import 'package:http/http.dart' as http; + +import 'package:flutter/cupertino.dart'; + +import 'package:shared_preferences/shared_preferences.dart'; + +class TagihanDetailScreen extends StatelessWidget{ + const TagihanDetailScreen({super.key, required this.tagihanToView}); + final TagihanModel tagihanToView; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Detail Tagihan"), + centerTitle: true, + leading: IconButton(icon: Icon(Icons.arrow_back_ios), onPressed: () + { + Navigator.pushNamed( + context, HomeScreen.routeName); + },), + ), + body: Column( + children: [ + Expanded(child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(kDefaultPadding), + topRight: Radius.circular(kDefaultPadding), + ), + color: kOtherColor + ), + child: Column ( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + + TagihanFieldRow(field: 'Kode Tagihan', value: tagihanToView.kode), + sizedBox, + TagihanFieldRow(field: 'Tanggal Terbuat', value: convertTanggal(tagihanToView.tanggalTerbuat)), + sizedBox, + TagihanFieldRow(field: 'Tanggal Bayar', value: convertTanggal(tagihanToView.tanggalTerbuat)), + sizedBox, + TagihanFieldRow(field: 'Status', value: getStatus(tagihanToView.isPaid)), + sizedBox, + TagihanFieldRow(field: 'Jumlah Tagihan', value:tagihanToView.jumlahTagihan.toString()), + sizedBox, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (tagihanToView.isPaid == false) ...[ + ConfirmationDialog(tagihan: tagihanToView), + ], + ], + ) + ], + ), + )), + ], + ), + + ); + } +} + +String convertTanggal(String dateTime) { + String tanggal = dateTime.substring(0,10); + return tanggal; +} + +String getStatus(bool isPaid) { + if (isPaid) { + return 'Lunas'; + + } else { + return 'Belum Dibayar'; + } +} + + +class TagihanFieldRow extends StatelessWidget { + const TagihanFieldRow({Key? key, required this.field, required this.value}) + : super(key: key); + final String field; + final String value; + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + field, + style: Theme.of(context).textTheme.caption!.copyWith( + color: kTextBlackColor, + ), + ), + Text(value, style: Theme.of(context).textTheme.subtitle2!.copyWith( + color: kTextBlackColor + )), + ], + ); + } +} + +class ConfirmationDialog extends StatelessWidget { + const ConfirmationDialog({Key? key, required this.tagihan}) + :super(key: key); + + final TagihanModel tagihan; + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: () => showDialog<String>( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text('Apakah Anda yakin ingin melakukan pembayaran untuk ' + this.tagihan.kode + ' sebesar ' + this.tagihan.jumlahTagihan.toString() + '?'), + content: const Text('Apakah Anda yakin ingin melakukan pembayaran?'), + actions: <Widget>[ + TextButton( + onPressed: () => Navigator.pop(context, 'Batal'), + child: const Text('Batal'), + ), + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PayTagihanResultScreen(tagihanToPay: tagihan) + ), + ); + }, + child: const Text('Bayar'), + ), + ], + ), + ), + child: const Text('Bayar Tagihan'), + ); + } +} diff --git a/rumahSehat_mobile/lib/url_settings.dart b/rumahSehat_mobile/lib/url_settings.dart index 072ec70e7c51ac411dd412f5262c7d7659fd4472..a036a9a884e04d0af57d1f6836b7d25ed7a9b022 100644 --- a/rumahSehat_mobile/lib/url_settings.dart +++ b/rumahSehat_mobile/lib/url_settings.dart @@ -1,5 +1,13 @@ -const String base_url = "http://172.20.10.7:8081/api"; +<<<<<<< HEAD +import 'package:shared_preferences/shared_preferences.dart'; + +const String base_url = "http://10.5.90.12:8081/api"; + +======= +const String base_url = "http://10.5.252.146:8081/api"; +>>>>>>> 228646434f6ccbedf90e2ae3bc075765875c277f const String appointment_url = base_url + "/appointment"; +const String resep_url = base_url + "/appointment"; const String add_appointment_url = appointment_url + "/add"; const String doctor_url = base_url + "/dokter"; const String get_alldoctor_url = doctor_url + "/viewAll"; @@ -7,4 +15,13 @@ const String get_allappointment_url = appointment_url + "/viewAll"; const String get_appointment_url = appointment_url + "/view"; const String pasien_url = base_url + "/pasien"; const String add_pasien_url = pasien_url + "/add"; -const String auth_login = base_url + "/auth/login"; \ No newline at end of file + +const String auth_login = base_url + "/auth/login"; +const String get_all_tagihan_url = base_url + "/tagihan/viewAll"; +const String pay_tagihan = base_url + "/tagihan/pay"; + +const String get_pasien_url = pasien_url + "/view"; +const String get_resep_url = resep_url + "/view"; +const String topup_url = pasien_url + "/view/topup"; + + diff --git a/rumahSehat_mobile/lib/user_page/PasienModel.dart b/rumahSehat_mobile/lib/user_page/PasienModel.dart new file mode 100644 index 0000000000000000000000000000000000000000..890a1cf27dc9da6d5d7021380c51597eb05b7102 --- /dev/null +++ b/rumahSehat_mobile/lib/user_page/PasienModel.dart @@ -0,0 +1,25 @@ +class PasienModel { + final String username; + final String nama; + final String email; + final int umur; + final int saldo; + + const PasienModel({ + required this.username, + required this.nama, + required this.email, + required this.umur, + required this.saldo, + }); + + factory PasienModel.fromJson(Map<String, dynamic> json) { + return PasienModel( + username: json['username'], + nama: json['nama'], + email: json['email'], + umur: json['umur'], + saldo: json['saldo'], + ); + } +} \ No newline at end of file diff --git a/rumahSehat_mobile/lib/user_page/top_up_saldo.dart b/rumahSehat_mobile/lib/user_page/top_up_saldo.dart index 525fc182ab5b8a0b48a672fbf20346ef220c1329..dd536aeb0d746d60f709d644b1627eb9e6cbfc56 100644 --- a/rumahSehat_mobile/lib/user_page/top_up_saldo.dart +++ b/rumahSehat_mobile/lib/user_page/top_up_saldo.dart @@ -1,14 +1,99 @@ import 'package:flutter/material.dart'; +import 'package:rumahsehat_mobile/url_settings.dart'; import 'package:sizer/sizer.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:rumahsehat_mobile/fragments.dart'; -import 'package:rumahsehat_mobile/home_page/home.dart'; import 'package:rumahsehat_mobile/user_page/view_user_profile.dart'; +import 'package:group_button/group_button.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:rumahsehat_mobile/user_page/PasienModel.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; -class TopUpSaldoScreen extends StatelessWidget { +class TopUpSaldoScreen extends StatefulWidget { const TopUpSaldoScreen({Key? key}) : super(key: key); static String routeName = "TopUpSaldoScreen"; + @override + TopUpSaldoScreenState createState() { + return TopUpSaldoScreenState(); + } +} + +class TopUpSaldoScreenState extends State<TopUpSaldoScreen> { + GlobalKey<FormState> formKey = GlobalKey<FormState>(); + final String urlProfile = get_pasien_url; + final String urlTopUp = topup_url; + late Future<PasienModel> futurePasienTUData; + late String pasienResBody; + + // Important Top Up Data + int currentSaldo = 0; + int valueIndex = 0; + int topUpAmount = 0; + + Future<PasienModel> getUserData() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String? _username = prefs.getString('username'); + var res = await http + .get(Uri.parse(urlProfile + "/$_username"), + headers: <String, String>{ + 'Content-Type' : 'application/json;charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken' + } + ); + pasienResBody = res.body; + // final Map parsed = json.decode(res.body); + // currentSaldo = parsed['saldo']; + + return PasienModel.fromJson(jsonDecode(res.body)); + } + + @override + void initState() { + super.initState(); + futurePasienTUData = getUserData(); + } + + String updateJson( + String json, + void Function(Map<String, dynamic>) update, + ) { + final data = jsonDecode(json); + update(data); + return jsonEncode(data); + } + + Future<bool> updateSaldo() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String? _username = prefs.getString('username'); + final response = await http.put( + Uri.parse(urlTopUp + "/$_username"), + headers: <String, String>{ + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken', + }, + body: pasienResBody = updateJson(pasienResBody, (json) { + if (json['saldo'] != null && json['saldo'] is int) { + int temp = json['saldo']; + print("Saldo sebelum: " + temp.toString()); + json['saldo'] = temp + topUpAmount; + print("Saldo sesudah: " + json['saldo'].toString()); + } + }) + ); + + if (response.statusCode == 200) { + return Future<bool>.value(true); + } + else { + // throw Exception("failed"); + return Future<bool>.value(false); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -20,20 +105,143 @@ class TopUpSaldoScreen extends StatelessWidget { context, UserProfileScreen.routeName); },), ), - body: Container( - width: 100.w, - decoration: BoxDecoration( - color: kOtherColor, - borderRadius: kTopBorderRadius, - ), - child: Column( - children: [ - MyCard( - balance: 100000, + body: FutureBuilder<PasienModel>( + future: futurePasienTUData, + builder: (context, AsyncSnapshot<PasienModel> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return const Center( + child: CircularProgressIndicator(), + ); + default: + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Container( + width: 100.w, + decoration: BoxDecoration( + color: kOtherColor, + borderRadius: kTopBorderRadius, + ), + child: Form ( + key: formKey, + child: Column( + children: [ + MyCard( + balance: snapshot.data!.saldo, + ), + Padding( + padding: const EdgeInsets.only(top: 25), + child: Center( + child: Text( + "Select your Top Up Amount:", + style: GoogleFonts.poppins( + color: kTextBlackColor, + fontSize:16, + fontWeight: FontWeight.w500, + ), + ), + ) + ), + Padding( + padding: const EdgeInsets.all(25.0), + child: Center( + child: GroupButton( + borderRadius: BorderRadius.circular(25), + spacing: 5, + mainGroupAlignment: MainGroupAlignment.center, + crossGroupAlignment: CrossGroupAlignment.center, + groupRunAlignment: GroupRunAlignment.spaceEvenly, + buttons: [ + "Rp25.000", + "Rp50.000", + "Rp100.000", + "Rp150.000", + "Rp200.000", + "Rp250.000", + "Rp300.000", + "Rp500.000", + "Rp1.000.000", + ], + isRadio: true, + onSelected: (index, isSelected) => valueIndex = index, + ), + ) + ), + Container( + child: OutlinedButton( + style: OutlinedButton.styleFrom( + side: BorderSide(color: Colors.green, width: 1), //<-- SEE HERE + ), + onPressed: () async { + if (valueIndex == 0) { + topUpAmount = 25000; + print(topUpAmount); + } else if (valueIndex == 1) { + topUpAmount = 50000; + print(topUpAmount); + } else if (valueIndex == 2) { + topUpAmount = 100000; + print(topUpAmount); + } else if (valueIndex == 3) { + topUpAmount = 150000; + print(topUpAmount); + } else if (valueIndex == 4) { + topUpAmount = 200000; + print(topUpAmount); + } else if (valueIndex == 5) { + topUpAmount = 250000; + print(topUpAmount); + } else if (valueIndex == 6) { + topUpAmount = 300000; + print(topUpAmount); + } else if (valueIndex == 7) { + topUpAmount = 500000; + print(topUpAmount); + } else { + topUpAmount = 1000000; + print(topUpAmount); + } + final validated = formKey.currentState!.validate(); + if (validated){ + print("Form Key Validate!"); + formKey.currentState!.save(); + bool response = await updateSaldo(); + if (response == true) { + Navigator.pushNamed( + context, UserProfileScreen.routeName); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Top Up Saldo Berhasil')), + ); + } + else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Top Up Saldo Gagal')), + ); + } + print(response.toString()); + } + else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Top Up Saldo Gagal')), + ); + } + }, + child: Text( + "Confirm", + style: TextStyle( + color: Colors.green, + ), + ), + ), + )] + ) + ) + ); + } + } + } ) - ] - ) - ) ); } } @@ -54,7 +262,22 @@ class MyCard extends StatelessWidget { padding: EdgeInsets.all(20), margin: EdgeInsets.only(top: 50), decoration: BoxDecoration( - color: kSecondaryColor, + gradient: + LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + stops: [ + 0.1, + 0.9, + // 0.6, + // 0.9, + ], + colors: [ + Color(0xffaaccff), + Color(0xff60a4ff), + // Color(0xFF2D89FF) + ], + ), borderRadius: BorderRadius.circular(12) ), child: Column( diff --git a/rumahSehat_mobile/lib/user_page/view_user_profile.dart b/rumahSehat_mobile/lib/user_page/view_user_profile.dart index b34a7df80f6055a7b3b4b7fb69edf669280cda86..9c3155f117222323b7f39dbd7584823597ea5c62 100644 --- a/rumahSehat_mobile/lib/user_page/view_user_profile.dart +++ b/rumahSehat_mobile/lib/user_page/view_user_profile.dart @@ -1,12 +1,71 @@ import 'package:flutter/material.dart'; +import 'package:rumahsehat_mobile/register_page/login_page.dart'; import 'package:sizer/sizer.dart'; import 'package:rumahsehat_mobile/fragments.dart'; import 'package:rumahsehat_mobile/home_page/home.dart'; import 'package:rumahsehat_mobile/user_page/top_up_saldo.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'package:rumahsehat_mobile/url_settings.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:rumahsehat_mobile/user_page/PasienModel.dart'; +import 'package:rumahsehat_mobile/login.dart'; -class UserProfileScreen extends StatelessWidget { - const UserProfileScreen({Key? key}) : super(key: key); +class UserProfileScreen extends StatefulWidget { static String routeName = "UserProfileScreen"; + const UserProfileScreen({Key? key,}) : super(key: key); + + @override + UserProfileState createState() => UserProfileState(); +} + +class UserProfileState extends State<UserProfileScreen> { + final String urlProfile = get_pasien_url; + late Future<PasienModel> futurePasienData; + + final Future<SharedPreferences> _prefs = SharedPreferences.getInstance(); + late Future<String> _email; + late Future<String> _username; + late Future<String> _jwtToken; + + Future<PasienModel> getUserData() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? _jwtToken = prefs.getString('jwtToken'); + String? _username = prefs.getString('username'); + var res = await http + .get(Uri.parse(urlProfile + "/$_username"), + headers: <String, String>{ + 'Content-Type' : 'application/json;charset=UTF-8', + 'Authorization' : 'Bearer $_jwtToken' + } + ); + + return PasienModel.fromJson(jsonDecode(res.body)); + } + + @override + void initState() { + super.initState(); + _email = _prefs.then((SharedPreferences prefs) { + return prefs.getString('email') ?? ''; + }); + _username = _prefs.then((SharedPreferences prefs) { + return prefs.getString('username') ?? ''; + }); + _jwtToken = _prefs.then((SharedPreferences prefs) { + return prefs.getString('jwtToken') ?? ''; + }); + futurePasienData = getUserData(); + } + + Future<void> _logout() async { + final SharedPreferences prefs = await _prefs; + setState(() { + prefs.remove('email'); + prefs.remove('username'); + prefs.remove('jwtToken'); + }); + } @override Widget build(BuildContext context) { @@ -19,83 +78,122 @@ class UserProfileScreen extends StatelessWidget { context, HomeScreen.routeName); },), ), - body: Container( - color: kOtherColor, - child: Column( - children: [ - Container( - width: 100.w, - height: SizerUtil.deviceType == DeviceType.tablet ? 19.h : 15.h, - decoration: BoxDecoration( - color: kPrimaryColor, - borderRadius: kBottomBorderRadius, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircleAvatar( - radius: - SizerUtil.deviceType == DeviceType.tablet ? 12.w : 13.w, - backgroundColor: kOtherColor, - backgroundImage: - AssetImage('assets/images/avatar-male.png'), - ), - kWidthSizedBox, - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'John Doe', - style: Theme.of(context).textTheme.subtitle1, - ), - Text( - 'Role: Pasien', - style: Theme.of(context).textTheme.subtitle2, - ), - ], - ) - ], - ), - ), - sizedBox, - ProfileDetailColumn( - title: 'Username', - value: 'John Doe', - ), - ProfileDetailColumn( - title: 'Email', - value: 'johndoe@ui.ac.id', - ), - ProfileDetailColumn( - title: 'Umur', - value: '21', - ), - ProfileDetailColumn( - title: 'Saldo', - value: 'Rp 100000', - ), - Container( - margin: const EdgeInsets.only(top: 15.0), - child: OutlinedButton( - style: OutlinedButton.styleFrom( - side: BorderSide(color: Colors.green, width: 1), //<-- SEE HERE - ), - onPressed: () { - Navigator.pushNamed( - context, TopUpSaldoScreen.routeName); - }, - child: Text( - "Top Up Saldo", - style: TextStyle( - color: Colors.green, - ), - ), - ), - ) - ], - ), - ), + body: FutureBuilder<PasienModel>( + future: futurePasienData, + builder: (context, AsyncSnapshot<PasienModel> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return const Center( + child: CircularProgressIndicator(), + ); + default: + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Container( + color: kOtherColor, + child: Column( + children: [ + Container( + width: 100.w, + height: SizerUtil.deviceType == DeviceType.tablet ? 19.h : 15.h, + decoration: BoxDecoration( + color: kPrimaryColor, + borderRadius: kBottomBorderRadius, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircleAvatar( + radius: + SizerUtil.deviceType == DeviceType.tablet ? 12.w : 13.w, + backgroundColor: kOtherColor, + backgroundImage: + AssetImage('assets/images/avatar-male.png'), + ), + kWidthSizedBox, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + snapshot.data!.nama, + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + 'Role: Pasien', + style: Theme.of(context).textTheme.subtitle2, + ), + ], + ) + ], + ), + ), + sizedBox, + ProfileDetailColumn( + title: 'Username', + value: snapshot.data!.username, + ), + ProfileDetailColumn( + title: 'Email', + value: snapshot.data!.email, + ), + ProfileDetailColumn( + title: 'Umur', + value: snapshot.data!.umur.toString(), + ), + ProfileDetailColumn( + title: 'Saldo', + value: snapshot.data!.saldo.toString(), + ), + Container( + margin: const EdgeInsets.only(top: 15.0), + child: OutlinedButton( + style: OutlinedButton.styleFrom( + side: BorderSide(color: Colors.green, width: 1), //<-- SEE HERE + ), + onPressed: () { + Navigator.pushNamed( + context, TopUpSaldoScreen.routeName); + }, + child: Text( + "Top Up Saldo", + style: TextStyle( + color: Colors.green, + ), + ), + ), + ), + Container( + margin: const EdgeInsets.only(top: 15.0), + child: OutlinedButton( + style: OutlinedButton.styleFrom( + side: BorderSide(color: Colors.red, width: 1), //<-- SEE HERE + ), + onPressed: () { + _logout(); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => + LoginPage()), + ModalRoute.withName("/login")); + }, + child: Text( + "Logout", + style: TextStyle( + color: Colors.red, + ), + ), + ), + ) + ], + ), + ); + } + } + } + ) ); } } diff --git a/rumahSehat_mobile/pubspec.lock b/rumahSehat_mobile/pubspec.lock index 5a9889c9d9b4e34c80125ea01c3045ca7a323b03..e383465c9934e93aee0e14861c36924d348cf861 100644 --- a/rumahSehat_mobile/pubspec.lock +++ b/rumahSehat_mobile/pubspec.lock @@ -135,6 +135,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + group_button: + dependency: "direct main" + description: + name: group_button + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.1" hexcolor: dependency: "direct main" description: @@ -310,6 +317,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.4" + quickalert: + dependency: "direct main" + description: + name: quickalert + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" select_form_field: dependency: "direct main" description: diff --git a/rumahSehat_mobile/pubspec.yaml b/rumahSehat_mobile/pubspec.yaml index 137e7c3531c4c1b97903169388adc5ab33836e18..e3909e8955e79b7506a3056df0ac45c7fdc6e29f 100644 --- a/rumahSehat_mobile/pubspec.yaml +++ b/rumahSehat_mobile/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: flutter_datetime_picker: ^1.5.1 # intl: ^0.16.1 carousel_slider: ^1.3.0 + group_button: ^2.4.1 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -52,6 +53,7 @@ dependencies: font_awesome_flutter: ^9.1.0 otp_text_field: ^1.1.1 intl: ^0.17.0 + quickalert: ^1.0.1 dev_dependencies: flutter_test: