diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/OfferPageController.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/OfferPageController.java index 9ccfcf6b8bc5520b6902771ab8846a7c2993d6ae..1a9a84181bc4277f2325171f0c5c9be1d3289f1a 100644 --- a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/OfferPageController.java +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/OfferPageController.java @@ -10,9 +10,15 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import vt.CS5934.SwitchRoom.models.ResponseModel; import vt.CS5934.SwitchRoom.models.UserOfferModel; +import vt.CS5934.SwitchRoom.models.WishlistMatchRequestInfo; import vt.CS5934.SwitchRoom.services.OfferPageService; -@CrossOrigin +import java.util.ArrayList; + +@CrossOrigin( + allowCredentials = "true", + origins = {"http://localhost:8080/"} +) @RestController @RequestMapping("offer") public class OfferPageController { @@ -25,8 +31,8 @@ public class OfferPageController { * This class will fetch user's offer from DB and send to front end * @return ResponseModel contains offer data */ - @GetMapping("/{userId}") - public ResponseModel getUserOfferInfo(@PathVariable Long userId){ + @GetMapping + public ResponseModel getUserOfferInfo(@CookieValue(value = "userId") Long userId){ ResponseModel responseModel = new ResponseModel(); try{ responseModel.setMessage("Success"); @@ -51,7 +57,7 @@ public class OfferPageController { responseModel.setData(offerPageService.saveNewUserOffer(offerModel)); return responseModel; }catch (Exception e){ - logger.error("Error in createNewUserOffer: "+e); + logger.error("Error in createNewUserOffer: "+e.fillInStackTrace()); responseModel.setMessage("Failed, Reason: " + e); responseModel.setStatus(HttpStatus.NOT_FOUND); responseModel.setData(null); @@ -60,12 +66,12 @@ public class OfferPageController { } @PostMapping("/updateOffer") - public ResponseModel updateUserOffer(UserOfferModel offerModel){ + public ResponseModel updateUserOffer(@RequestBody UserOfferModel offerModel){ offerPageService.removeOfferFromMatchedTable(offerModel.getUserId()); return createNewUserOffer(offerModel); } - @DeleteMapping("/{userId}") + @DeleteMapping("/deleteOffer/{userId}") public ResponseModel deleteUserOffer(@PathVariable Long userId){ ResponseModel responseModel = new ResponseModel(); try{ @@ -83,4 +89,26 @@ public class OfferPageController { } } + @GetMapping("/wishlistMatchRequestInfoList") + public ResponseModel getWishlistMatchRequestInfoList(@CookieValue(value = "userId") Long userId){ + ResponseModel responseModel = new ResponseModel(); + try{ + responseModel.setMessage("Success"); + responseModel.setStatus(HttpStatus.OK); + responseModel.setData(offerPageService.getWishlistMatchRequestInfoList(userId)); + return responseModel; + }catch (Exception e){ + logger.error("Error in getWishlistMatchRequestInfoList: "+e.fillInStackTrace()); + responseModel.setMessage("Failed, Reason: " + e); + responseModel.setStatus(HttpStatus.NOT_FOUND); + responseModel.setData(new ArrayList<WishlistMatchRequestInfo>()); + return responseModel; + } + } + } +/* +Change logs: +Date | Author | Description +2022-11-05 | Fangzheng Zhang | add getWishlistMatchRequestInfoList function + */ diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/WishlistPageController.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/WishlistPageController.java index 2f6a29ff46a65a9c0f486f5ea38f09c54bc5615f..869e2825b35b5451ddb386ce9b8d910ba7c967b9 100644 --- a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/WishlistPageController.java +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/WishlistPageController.java @@ -5,11 +5,17 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import vt.CS5934.SwitchRoom.models.OfferMatchRequestInfo; import vt.CS5934.SwitchRoom.models.ResponseModel; import vt.CS5934.SwitchRoom.models.WishlistItemModel; import vt.CS5934.SwitchRoom.services.WishlistPageService; -@CrossOrigin +import java.util.List; + +@CrossOrigin( + allowCredentials = "true", + origins = {"http://localhost:8080/"} +) @RestController @RequestMapping("wishlist") public class WishlistPageController { @@ -19,8 +25,8 @@ public class WishlistPageController { @Autowired WishlistPageService wishlistPageService; - @GetMapping("/{userId}") - public ResponseModel getWishlistList(@PathVariable Long userId){ + @GetMapping + public ResponseModel getWishlistList(@CookieValue(value = "userId") Long userId){ ResponseModel responseModel = new ResponseModel(); try{ responseModel.setMessage("Success"); @@ -36,8 +42,8 @@ public class WishlistPageController { } } - @PostMapping("/newWishlistItem/{userId}") - public ResponseModel saveNewWishlistItem(@PathVariable Long userId, + @PostMapping("/newWishlistItem") + public ResponseModel saveNewWishlistItem(@CookieValue(value = "userId") Long userId, @RequestBody WishlistItemModel wishlistItemModel){ ResponseModel responseModel = new ResponseModel(); try{ @@ -71,10 +77,11 @@ public class WishlistPageController { } } - @DeleteMapping("/deleteWishlistItem/{userId}") - public ResponseModel deleteWishlistItem(@PathVariable Long userId, @RequestParam Long wishlistItemId){ + @DeleteMapping("/deleteWishlistItem/{wishlistItemId}") + public ResponseModel deleteWishlistItem(@PathVariable Long wishlistItemId){ ResponseModel responseModel = new ResponseModel(); try{ + Long userId = wishlistPageService.getPairedUserId(wishlistItemId); wishlistPageService.deleteWishlistItem(wishlistItemId); responseModel.setMessage("Success"); responseModel.setStatus(HttpStatus.OK); @@ -88,11 +95,48 @@ public class WishlistPageController { return responseModel; } } + + @GetMapping("/loadOfferMatchList/{wishlistItemId}") + public ResponseModel getOfferMatchList(@PathVariable Long wishlistItemId){ + ResponseModel responseModel = new ResponseModel(); + try{ + List<OfferMatchRequestInfo> offerMatchRequestInfoList = + wishlistPageService.getOfferMatchList(wishlistItemId); + responseModel.setMessage("Success"); + responseModel.setStatus(HttpStatus.OK); + responseModel.setData(offerMatchRequestInfoList); + return responseModel; + }catch (Exception e){ + logger.error("Error in getOfferMatchList: "+e.fillInStackTrace()); + responseModel.setMessage("getOfferMatchList Failed, Reason: " + e); + responseModel.setStatus(HttpStatus.NOT_FOUND); + responseModel.setData(null); + return responseModel; + } + } + @PostMapping("/loadOfferMatchCount") + public ResponseModel getOfferMatchCount(@RequestBody List<Long> wishlistItemIdList){ + ResponseModel responseModel = new ResponseModel(); + try{ + List<Long> offerMatchCount = wishlistPageService.getOfferMatchCount(wishlistItemIdList); + responseModel.setMessage("Success"); + responseModel.setStatus(HttpStatus.OK); + responseModel.setData(offerMatchCount); + return responseModel; + }catch (Exception e){ + logger.error("Error in getOfferMatchCount: "+e.fillInStackTrace()); + responseModel.setMessage("getOfferMatchCount Failed, Reason: " + e); + responseModel.setStatus(HttpStatus.NOT_FOUND); + responseModel.setData(null); + return responseModel; + } + } } /* Change logs: Date | Author | Description 2022-10-21 | Fangzheng Zhang | create class and init - +2022-11-03 | Fangzheng Zhang | Remove user id in the parameter, since cookie is ready +2022-11-05 | Fangzheng Zhang | add getOfferMatchList function and getOfferMatchCount function */ \ No newline at end of file diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/models/OfferMatchRequestInfo.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/models/OfferMatchRequestInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..0a2378da9c1bb75d0f58229b0ce81e5ff9f00777 --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/models/OfferMatchRequestInfo.java @@ -0,0 +1,73 @@ +package vt.CS5934.SwitchRoom.models; + +import lombok.Data; + +import java.util.Date; + +@Data +public class OfferMatchRequestInfo { + private Long offerOwnerId; + private Long wishListId; + private Date startTime; + private Date endTime; + private Integer zipCode; + private String hostName; + + public OfferMatchRequestInfo(Long offerOwnerId, Long wishListId, Date startTime, Date endTime, + Integer zipCode, String hostName) { + this.offerOwnerId = offerOwnerId; + this.wishListId = wishListId; + this.startTime = startTime; + this.endTime = endTime; + this.zipCode = zipCode; + this.hostName = hostName; + } + + public Long getOfferOwnerId() { + return offerOwnerId; + } + + public void setOfferOwnerId(Long offerOwnerId) { + this.offerOwnerId = offerOwnerId; + } + + public Long getWishListId() { + return wishListId; + } + + public void setWishListId(Long wishListId) { + this.wishListId = wishListId; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public Integer getZipCode() { + return zipCode; + } + + public void setZipCode(Integer zipCode) { + this.zipCode = zipCode; + } + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } +} diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/models/WishlistMatchRequestInfo.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/models/WishlistMatchRequestInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..3cacc490f40feac3566ad443d9f55b6b4cdfcfdb --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/models/WishlistMatchRequestInfo.java @@ -0,0 +1,83 @@ +package vt.CS5934.SwitchRoom.models; + +import lombok.Data; + +import java.util.Date; + +@Data +public class WishlistMatchRequestInfo { + private Long wishlistOwnerId; + private Long wishlistId; + private Date startTime; + private Date endTime; + private String wishListOwnerName; + private Boolean hasOffer; + private Integer zipCode; + + public WishlistMatchRequestInfo(Long wishlistOwnerId, Long wishlistId, Date startTime, Date endTime, + String wishListOwnerName, Boolean hasOffer, Integer zipCode) { + this.wishlistOwnerId = wishlistOwnerId; + this.wishlistId = wishlistId; + this.startTime = startTime; + this.endTime = endTime; + this.wishListOwnerName = wishListOwnerName; + this.hasOffer = hasOffer; + this.zipCode = zipCode; + } + + public Long getWishlistOwnerId() { + return wishlistOwnerId; + } + + public void setWishlistOwnerId(Long wishlistOwnerId) { + this.wishlistOwnerId = wishlistOwnerId; + } + + public Long getWishlistId() { + return wishlistId; + } + + public void setWishlistId(Long wishlistId) { + this.wishlistId = wishlistId; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public String getWishListOwnerName() { + return wishListOwnerName; + } + + public void setWishListOwnerName(String wishListOwnerName) { + this.wishListOwnerName = wishListOwnerName; + } + + public Boolean getHasOffer() { + return hasOffer; + } + + public void setHasOffer(Boolean hasOffer) { + this.hasOffer = hasOffer; + } + + public Integer getZipCode() { + return zipCode; + } + + public void setZipCode(Integer zipCode) { + this.zipCode = zipCode; + } +} diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/MatchedWishlistRecordRepository.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/MatchedWishlistRecordRepository.java index 8835ae85a28224d458c4eae65787a3d77e540898..a299f79b0d3f7a89e4c8428d01c4f3ad721a5061 100644 --- a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/MatchedWishlistRecordRepository.java +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/MatchedWishlistRecordRepository.java @@ -4,7 +4,13 @@ import org.springframework.data.jpa.repository.JpaRepository; import vt.CS5934.SwitchRoom.models.MatchedRecordIdModel; import vt.CS5934.SwitchRoom.models.MatchedWishlistRecordModel; +import java.util.List; + public interface MatchedWishlistRecordRepository extends JpaRepository<MatchedWishlistRecordModel, MatchedRecordIdModel> { + List<MatchedWishlistRecordModel> findAllByOfferId(Long offerId); + List<MatchedWishlistRecordModel> findAllByWishlistItemId(Long wishlistItemId); + void deleteAllByOfferId(Long offerId); void deleteAllByWishlistItemId(Long wishlistItemId); + Long countByWishlistItemId(Long wishlistItemId); } diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/UserOfferWishlistLookUpRepository.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/UserOfferWishlistLookUpRepository.java index 5a9f529e3a53b540506eeee87457c9c6de3d6b3e..02be9157138c577264aaeca9fca8a2d1be1fd4c0 100644 --- a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/UserOfferWishlistLookUpRepository.java +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/repositories/UserOfferWishlistLookUpRepository.java @@ -8,7 +8,7 @@ import java.util.List; public interface UserOfferWishlistLookUpRepository extends JpaRepository<UserOfferWishlistLookUpModel, Long> { List<UserOfferWishlistLookUpModel> findAllByUserId(Long userId); - UserOfferModel findByWishlistItemId(Long wishlistItemId); + UserOfferWishlistLookUpModel findByWishlistItemId(Long wishlistItemId); void deleteByWishlistItemId(Long wishlistItemId); } diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferPageService.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferPageService.java index 6842160775d9f9bed9af24b119512415b5b8cc8f..a1501db98129ccd5802277ba5967435dd0c4c8dd 100644 --- a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferPageService.java +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferPageService.java @@ -5,14 +5,13 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import vt.CS5934.SwitchRoom.models.StateCityLookupModel; -import vt.CS5934.SwitchRoom.models.UserOfferModel; -import vt.CS5934.SwitchRoom.repositories.MatchedWishlistRecordRepository; -import vt.CS5934.SwitchRoom.repositories.OfferWaitingMatchRepository; -import vt.CS5934.SwitchRoom.repositories.StateCityLookupRepository; -import vt.CS5934.SwitchRoom.repositories.UserOfferRepository; +import vt.CS5934.SwitchRoom.models.*; +import vt.CS5934.SwitchRoom.repositories.*; import vt.CS5934.SwitchRoom.utility.StateCodeMap; +import java.util.ArrayList; +import java.util.List; + @Service public class OfferPageService { private final Logger logger = LoggerFactory.getLogger(OfferPageService.class); @@ -25,6 +24,12 @@ public class OfferPageService { MatchedWishlistRecordRepository matchedWishlistRecordRepository; @Autowired OfferWaitingMatchRepository offerWaitingMatchRepository; + @Autowired + UserOfferWishlistLookUpRepository userOfferWishlistLookUpRepository; + @Autowired + UserRepository userRepository; + @Autowired + WishlistItemRepository wishlistItemRepository; public UserOfferModel getUserOfferInfo(Long userId) { UserOfferModel userOfferModel = userOfferRepository.findByUserId(userId); @@ -55,6 +60,8 @@ public class OfferPageService { } + + /** * This function will take a UserOfferModel. it will fill the StateCode with it first, * then check and update the StateCityCode. If DB do not have the StateCityCode, then build one and fill it in. @@ -77,6 +84,34 @@ public class OfferPageService { } offerModel.setStateCityCode(stateCityLookupModel.getStateCityCode()); } + + /** + * This service will fetch information from many table to get the WishlistMatchRequestInfo, so we can display it in + * the offer page + * @param userId The id of user who opened the offer page + * @return a list of WishlistMatchRequestInfo. + */ + public List<WishlistMatchRequestInfo> getWishlistMatchRequestInfoList(Long userId) { + List<WishlistMatchRequestInfo> wishlistMatchRequestInfoList = new ArrayList<>(); + List<MatchedWishlistRecordModel> matchedRecordList = matchedWishlistRecordRepository.findAllByOfferId(userId); + for(MatchedWishlistRecordModel matchedRecord : matchedRecordList){ + Long requestedWishlistId = matchedRecord.getWishlistItemId(); + Long wishlistOwnerId = userOfferWishlistLookUpRepository + .findByWishlistItemId(requestedWishlistId).getUserId(); + // get user information from userRepository, get wishlistItem information from wishlistItem table, + // check if the wishlistItem owner has Offer or not, if does, find zipcode. + UserModel wishlistOwnerInfo = userRepository.findByUserId(wishlistOwnerId.intValue()); + WishlistItemModel wishlistItem = wishlistItemRepository.findByWishlistItemId(requestedWishlistId); + UserOfferModel wishlistOwnerOfferModel = userOfferRepository.findByUserId(wishlistOwnerId); + WishlistMatchRequestInfo wishlistMatchRequestInfo = new WishlistMatchRequestInfo(wishlistOwnerId, + requestedWishlistId, wishlistItem.getStartTime(), wishlistItem.getEndTime(), + wishlistOwnerInfo.getFirstname() + " " + wishlistOwnerInfo.getLastname(), + wishlistOwnerOfferModel != null && wishlistOwnerOfferModel.getOffering(), + wishlistOwnerOfferModel == null ? null : wishlistOwnerOfferModel.getZipCode()); + wishlistMatchRequestInfoList.add(wishlistMatchRequestInfo); + } + return wishlistMatchRequestInfoList; + } } /* Change logs: diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/WishlistPageService.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/WishlistPageService.java index d09728fcd158a53f6b12859c6c067673bde1c0c8..b9b04765212f9fd4bd49f456cafa4cba8a8817ca 100644 --- a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/WishlistPageService.java +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/WishlistPageService.java @@ -6,10 +6,7 @@ package vt.CS5934.SwitchRoom.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import vt.CS5934.SwitchRoom.models.StateCityLookupModel; -import vt.CS5934.SwitchRoom.models.UserOfferModel; -import vt.CS5934.SwitchRoom.models.UserOfferWishlistLookUpModel; -import vt.CS5934.SwitchRoom.models.WishlistItemModel; +import vt.CS5934.SwitchRoom.models.*; import vt.CS5934.SwitchRoom.repositories.*; import vt.CS5934.SwitchRoom.utility.StateCodeMap; @@ -29,6 +26,10 @@ public class WishlistPageService { MatchedWishlistRecordRepository matchedWishlistRecordRepository; @Autowired WishlistWaitingMatchRepository wishlistWaitingMatchRepository; + @Autowired + UserOfferRepository userOfferRepository; + @Autowired + UserRepository userRepository; /** * This function will take userId and look into UserOfferWishlistLookUpModel DB and find all the wishlist item id @@ -91,6 +92,10 @@ public class WishlistPageService { return wishlistItemRepository.findByWishlistItemId(wishlistItemId); } + public Long getPairedUserId( Long wishlistItemId ){ + return userOfferWishlistLookUpRepository.findByWishlistItemId(wishlistItemId).getUserId(); + } + /** * This function will take a UserOfferModel. it will fill the StateCode with it first, @@ -114,6 +119,34 @@ public class WishlistPageService { } wishlistItemModel.setStateCityCode(stateCityLookupModel.getStateCityCode()); } + + /** + * This function is used to get the matched offers of the given wishlist item + * @param wishlistItemId the target id + * @return a list of matched offer info of the given wishlistItem + */ + public List<OfferMatchRequestInfo> getOfferMatchList(Long wishlistItemId) { + List<OfferMatchRequestInfo> offerMatchRequestInfoList = new ArrayList<>(); + List<MatchedWishlistRecordModel> matchedRecordList = + matchedWishlistRecordRepository.findAllByWishlistItemId(wishlistItemId); + matchedRecordList.forEach( matchedRecord ->{ + UserOfferModel userOfferModel = userOfferRepository.findByUserId(matchedRecord.getOfferId()); + UserModel userInfo = userRepository.findByUserId(userOfferModel.getUserId().intValue()); + offerMatchRequestInfoList.add(new OfferMatchRequestInfo(userOfferModel.getUserId(), + wishlistItemId, userOfferModel.getAvailableTimeStart(),userOfferModel.getAvailableTimeEnd(), + userOfferModel.getZipCode(), userInfo.getFirstname()+" "+ userInfo.getLastname())); + }); + return offerMatchRequestInfoList; + } + + public List<Long> getOfferMatchCount(List<Long> wishlistItemIdList) { + List<Long> countList = new ArrayList<>(); + wishlistItemIdList.forEach((wishListId ->{ + Long count = matchedWishlistRecordRepository.countByWishlistItemId(wishListId); + countList.add(count == null ? 0 : count); + })); + return countList; + } } /* Change logs: @@ -121,4 +154,5 @@ Date | Author | Description 2022-10-21 | Fangzheng Zhang | create class and init 2022-10-30 | Fangzheng Zhang | implement state city code feature 2022-11-03 | Fangzheng Zhang | handle update and deletion to matched table and waiting table +2022-11-05 | Fangzheng Zhang | Add getOfferMatchList function */ \ No newline at end of file diff --git a/FrontendFolder/switch-room/src/components/OfferPage.vue b/FrontendFolder/switch-room/src/components/OfferPage.vue index ca6a156e6fead738de0a8fae7db855b0b41410d1..ef74d1776090eab68e12cf64dc23c17a7d296d97 100644 --- a/FrontendFolder/switch-room/src/components/OfferPage.vue +++ b/FrontendFolder/switch-room/src/components/OfferPage.vue @@ -1,6 +1,6 @@ <template> <el-row :gutter="20"> - <el-col :span="4"><div class="grid-content ep-bg-purple" /></el-col> + <el-col :span="3"><div class="grid-content ep-bg-purple" /></el-col> <el-col :span="12"> <el-card style="width: 100%"> <template #header> @@ -19,23 +19,25 @@ status-icon > <el-form-item label="Located City" prop="spaceLocateCity"> - <el-col :span="8"> - <el-input v-model="ruleForm.spaceLocateCity" /> + <el-col :span="15"> + <el-input v-model="ruleForm.spaceLocateCity" :readonly="buttonState === 'edit'"/> </el-col> </el-form-item> <el-form-item label="State" prop="state"> <el-col :span="8"> <el-select v-model="ruleForm.state" - placeholder="Select state"> + placeholder="Select state" + :disabled="buttonState === 'edit'" + > <el-option v-for="(state_item, index) in USA_STATE_INITAL_LIST" :label="state_item" :value="state_item" /> </el-select> </el-col> </el-form-item> <el-form-item label="Zip Code" prop="zipCode"> - <el-col :span="5"> - <el-input v-model="ruleForm.zipCode" placeholder="24061.." /> + <el-col :span="7"> + <el-input v-model="ruleForm.zipCode" placeholder="24061" :readonly="buttonState === 'edit'"/> </el-col> </el-form-item> <el-col :span="24"> @@ -43,6 +45,7 @@ <el-select v-model="ruleForm.spaceType" placeholder="Please select your Space Type" + :disabled="buttonState === 'edit'" > <el-option label="Apartment (No Roommates)" @@ -75,13 +78,13 @@ :required="ruleForm.spaceType === 'other'" > <el-col :span="8"> - <el-input v-model="ruleForm.otherSpaceType" /> + <el-input v-model="ruleForm.otherSpaceType" :readonly="buttonState === 'edit'"/> </el-col> </el-form-item> <el-form-item label="Space Available for Offering?"> <el-col :span="2"> <el-form-item prop="offering"> - <el-switch v-model="ruleForm.offering" /> + <el-switch v-model="ruleForm.offering" :disabled="buttonState === 'edit'"/> </el-form-item> </el-col> </el-form-item> @@ -99,6 +102,7 @@ label="Pick a date" placeholder="Pick a date" style="width: 100%" + :readonly="buttonState === 'edit'" /> </el-form-item> </el-col> @@ -112,6 +116,7 @@ label="Pick a time" placeholder="Pick a time" style="width: 100%" + :readonly="buttonState === 'edit'" /> </el-form-item> </el-col> @@ -123,35 +128,60 @@ prop="maxNumberOfPeople" > <el-col :span="4"> - <el-input v-model="ruleForm.maxNumberOfPeople" /> + <el-input v-model="ruleForm.maxNumberOfPeople" :readonly="buttonState === 'edit'"/> </el-col> </el-form-item> <el-form-item></el-form-item> <el-form-item label="Space Details:" prop="spaceDetails"> <el-col :span="16" - ><el-input v-model="ruleForm.spaceDetails" type="textarea" + ><el-input v-model="ruleForm.spaceDetails" type="textarea" :readonly="buttonState === 'edit'" /></el-col> </el-form-item> - <el-form-item> + <el-form-item v-if="buttonState === 'create'"> <el-button type="primary" @click="submitForm(ruleFormRef)" - >Create</el-button - > + >Create</el-button> <el-button @click="resetForm(ruleFormRef)">Reset</el-button> </el-form-item> + <el-form-item v-if="buttonState === 'edit'"> + <el-button type="primary" @click="editForm()" + >Edit</el-button> + </el-form-item> + <el-form-item v-if="buttonState === 'update'"> + <el-button type="success" @click="updateForm(ruleFormRef)" + >Save</el-button> + <el-button type="danger" @click="deleteForm(ruleFormRef)">Delete</el-button> + </el-form-item> + </el-form> </el-card> </el-col> - <el-col :span="4"> - <el-card style="width: 100%" - ><template #header> + <el-col :span="6"> + <el-card style="width: 100%"> + <template #header> <div class="card-header"> <span>Match Request</span> </div> </template> - </el-card></el-col - > - <el-col :span="4"></el-col> +<!-- TODO --> + <el-card + v-for="(item, index) in matchRequestList.value" + shadow="hover" + style="width: 280px" + @click="selectMatchRequestItem(index)" + > + <time > {{formatDate(item.startTime)}} - {{formatDate(item.endTime)}}</time> + <div class="w-bottom"> + <span class="w-owner"> Wishlist Owner Name: {{item.wishListOwnerName}}</span> + <br> + <span class="w-zipCode" v-if="!item.hasOffer"> No Available Offer </span> + <span class="w-zipCode">Zip Code: {{item.zipCode}}</span> + </div> + </el-card> + + </el-card> + </el-col> + <el-col :span="2"></el-col> </el-row> </template> @@ -198,61 +228,90 @@ const rules = reactive<FormRules>({ ], }); // TODO: uncomment it when API connection ready -const userId = 233; let ruleForm = ref(new OfferFormModel()); +let buttonState = ref("create"); +let matchRequestList = reactive({value:[]}); onMounted(() => { -OfferPageService.getUserOfferInfoFromServer(userId).then( (data) => { - console.log("Receive user offer data: ", data); - if(data["data"] === null){ - // TODO: Handle fetch error - }else{ - ruleForm.value = data["data"]; - } - }) + loadInitOfferInfoPage(); + loadOfferPageMatchRequest(); }) +const loadInitOfferInfoPage = async () =>{ + await OfferPageService.getUserOfferInfoFromServer().then( (data) => { + console.log("Receive user offer data: ", data); + if(data["data"] === null){ + // TODO: Handle fetch error + }else{ + ruleForm.value = data["data"]; + if(ruleForm.value.spaceLocateCity == null || ruleForm.value.spaceLocateCity == ""){ + buttonState.value = "create"; + }else{ + buttonState.value = "edit"; + } + } + }); +} + +const loadOfferPageMatchRequest = async() =>{ + await OfferPageService.getWishlistMatchRequestInfoList().then( (data) =>{ + console.log("Fetching Offer Page Match Request Info: ", data); + matchRequestList.value = data["data"]; + }) +} + + const submitForm = async (formEl: FormInstance | undefined) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { - let result = OfferPageService.createNewUserOffer(ruleForm); // TODO: Check the return result console.log("Form Data before save in DB: ", ruleForm.value); OfferPageService.createNewUserOffer(ruleForm.value).then((data) => { console.log("Save user offer data: ", data); + ruleForm.value = data["data"]; + buttonState.value = "edit"; }) console.log("submit!"); } else { console.log("error submit!", fields); } - console.log(ruleForm); }); }; -const updateFrom = async (formEl: FormInstance | undefined) => { +const editForm = () => { + buttonState.value = "update"; +} + +const updateForm = async (formEl: FormInstance | undefined) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { - let result = OfferPageService.updateOffer(ruleForm); // TODO: Check the return result - console.log("update submit!"); + OfferPageService.updateOffer(ruleForm.value).then((data) =>{ + console.log("Update user offer data: ", data); + ruleForm.value = data["data"]; + buttonState.value = "edit"; + }) } else { console.log("error submit!", fields); } - console.log(ruleForm); }); }; -const deleteFrom = () => { +const deleteForm = async(formEl: FormInstance | undefined) => { // TODO: Check the return result - let result = OfferPageService.deleteOffer(userId); - console.log("Record deleted"); + await OfferPageService.deleteOffer(ruleForm.value.userId).then((data) =>{ + console.log("Deleting Offer Record"); + console.log("Message: " + data["message"]); + resetForm(); + buttonState.value = "create"; + }); }; -const resetForm = (formEl: FormInstance | undefined) => { - if (!formEl) return; - formEl.resetFields(); +const resetForm = () => { + let userId = ruleForm.value.userId; + ruleForm.value = new OfferFormModel(); ruleForm.value.userId = userId; }; @@ -260,4 +319,21 @@ const options = Array.from({ length: 10000 }).map((_, idx) => ({ value: `${idx + 1}`, label: `${idx + 1}`, })); + +const formatDate = (dateString) => { + const date = new Date(dateString); + return new Intl.DateTimeFormat('en-US').format(date); +} </script> + +<style scoped> +.time { + font-size: 12px; +} +.w-zipCode { + font-size: 12px; +} +.w-owner { + font-size: 12px; +} +</style> \ No newline at end of file diff --git a/FrontendFolder/switch-room/src/components/WishlistPage.vue b/FrontendFolder/switch-room/src/components/WishlistPage.vue index daa5f86be8ee78b5b12e8776651e082de0eb55b7..b3ebe41cba78ab444d82d342a52d2f0e8d940f5c 100644 --- a/FrontendFolder/switch-room/src/components/WishlistPage.vue +++ b/FrontendFolder/switch-room/src/components/WishlistPage.vue @@ -1,7 +1,7 @@ <template> <el-row :gutter="20"> - <el-col :span="4"><div class="grid-content ep-bg-purple" /></el-col> - <el-col :span="16"> + <el-col :span="2"><div class="grid-content ep-bg-purple" /></el-col> + <el-col :span="20"> <el-card style="width: 100%"> <template #header> <div class="card-header"> @@ -14,20 +14,28 @@ <!-- Aside Coding Area --> <el-aside width="300px"> <el-space direction="vertical" width="100%"> - <el-card - v-for="(item, index) in wishlistList.value" - shadow="hover" - style="width: 280px" - @click="selectItem(index)" + <el-badge class="item" + v-for="(item, index) in wishlistList.value" + :value="totalMatchCountList.value[index]" + :hidden = "totalMatchCountList.value[index] === 0" > - <span>{{ item.cityName }}</span> - <div class="bottom"> - <time class="time" - >"{{ item.startTime }} to {{ item.endTime }}"</time - > - </div> - </el-card> + <el-card + shadow="hover" + style="width: 280px" + @click="selectItem(index)" + > + <span>{{ item.cityName }}, {{ item.state }}</span> + <div class="bottom"> + <time class="time" + >"{{ formatDate(item.startTime) }} to {{ formatDate(item.endTime) }}"</time + > + </div> + </el-card> + + </el-badge> + <el-card + class="item" shadow="hover" style="width: 280px" @click="addNewWishlistItem()" @@ -54,17 +62,19 @@ <el-form-item></el-form-item> <el-form-item label="City Name:" prop="cityName"> - <el-input v-model="wishlistItem.cityName" /> + <el-input v-model="wishlistItem.cityName" :readonly="buttonState === 'edit'" /> </el-form-item> <el-form-item label="Zip Code:" prop="zipCode"> - <el-input v-model="wishlistItem.zipCode" /> + <el-input v-model="wishlistItem.zipCode" :readonly="buttonState === 'edit'"/> </el-form-item> - <el-form-item label="State:" prop="state"> + <el-form-item label="State:" prop="state"> <el-select v-model="wishlistItem.state" - placeholder="Please select state"> + placeholder="Please select state" + :disabled="buttonState === 'edit'" + > <el-option v-for="(state_item, index) in USA_STATE_INITAL_LIST" :label="state_item" :value="state_item" /> </el-select> @@ -78,6 +88,7 @@ label="Pick a date" placeholder="Pick a date" style="width: 100%" + :readonly="buttonState === 'edit'" /> </el-form-item> </el-form-item> @@ -90,6 +101,7 @@ label="Pick a date" placeholder="Pick a date" style="width: 100%" + :readonly="buttonState === 'edit'" /> </el-form-item> </el-form-item> @@ -99,21 +111,50 @@ v-model="wishlistItem.details" type="textarea" placeholder="Trip plan or want to visit places..." + :readonly="buttonState === 'edit'" /> </el-form-item> - <el-button type="primary" @click="submitForm(ruleFormRef)" - >Create</el-button - > - <el-button @click="resetForm(ruleFormRef)">Reset</el-button> + <el-button type="primary" v-if="buttonState === 'create'" @click="submitForm(ruleFormRef)" + >Create</el-button> + <el-button type="primary" v-if="buttonState === 'edit'" @click="onEdit(ruleFormRef)" + >Edit</el-button> + <el-button type="success" v-if="buttonState === 'update'" @click="updateForm(ruleFormRef)" + >Save</el-button> + <el-button type="danger" v-if="buttonState === 'update'" @click="deleteForm(ruleFormRef)"> + Delete</el-button> </el-form> </el-card> </el-main> + + <el-aside width="300px"> + <el-space direction="vertical" width="100%" :fill="true"> + <div class="card-header"> + <span>Matched Offer for: + {{wishlistItem.cityName}}, {{wishlistItem.state}} + </span> + </div> + <el-card + v-for="(item, index) in offerMatchList.value" + shadow="hover" + style="width: 280px" + @click="selectMatchOfferItem(index)" + > + <span> {{formatDate(item.startTime)}} - {{formatDate(item.endTime)}} </span> + <div> + <span class="o-zipCode"> Zip code: {{item.zipCode}} </span> + <br> + <span class="o-owner"> Host name: {{item.hostName}} </span> + </div> + </el-card> + </el-space> + </el-aside> </el-container> </div> </el-card> + </el-col> - <el-col :span="4"><div class="grid-content ep-bg-purple" /></el-col> + <el-col :span="2"><div class="grid-content ep-bg-purple" /></el-col> </el-row> </template> @@ -167,30 +208,73 @@ const rules = reactive<FormRules>({ ], }); -// TODO: uncomment it when API connection ready -const userId = 233; const wishlistList = reactive({value:[]}); const wishlistItem = ref(new WishlistItemModel()); wishlistItem.value.wishlistItemId = null; +let buttonState = ref("create"); +const selectedIdx = ref(0); +const offerMatchList = reactive({value:[]}); +const totalMatchCountList = reactive({value:[]}); onMounted(() => { - WishlistService.getUserWishlistInfo(userId).then((data)=>{ + selectedIdx.value = 0; + wishlistInitLoad(); +}) + +const onEdit = () =>{ + buttonState.value = "update"; +} + +const wishlistInitLoad = async() =>{ + await WishlistService.getUserWishlistInfo().then((data)=>{ console.log("Receiving wishlist list data", data); - if(data["data"] === null){ + if(data["data"] === null || data["data"].length === 0){ wishlistList.value = []; + buttonState.value = "create"; }else{ - wishlistList.value wishlistList.value = data["data"]; + selectItem(0); + buttonState.value = "edit"; + loadMatchNumbersForAllList(data["data"]); } }) +} -}) +const loadMatchNumbersForAllList = async (wishlistItemList: Array<WishlistItemModel>) =>{ + await WishlistService.loadMatchOfferNumbersFor(wishlistItemList).then((data) =>{ + console.log("Receiving offer match count list data: ", data); + if(data["data"] === null || data["data"].length === 0){ + for(let i=0; i<totalMatchCountList.value.length; ++i){ + totalMatchCountList.value.push(0); + } + }else{ + totalMatchCountList.value = data["data"]; + } + }) +} +const loadOfferMatchList = async () =>{ + await WishlistService.getOfferMatchList(wishlistItem.value.wishlistItemId).then((data) =>{ + console.log("Receiving offer match list data: ", data); + if(data["data"] === null || data["data"].length === 0){ + offerMatchList.value = []; + }else{ + offerMatchList.value = data["data"]; + } + }) +} +const formatDate = (dateString) => { + const date = new Date(dateString); + return new Intl.DateTimeFormat('en-US').format(date); +} function selectItem(idx: number) { console.log("Selected wishlist Item: " + idx); wishlistItem.value = reactive(wishlistList.value[idx]); + buttonState.value = "edit"; + selectedIdx.value = idx; + loadOfferMatchList(wishlistItem.value.wishlistItemId); } function addNewWishlistItem() { @@ -198,18 +282,21 @@ function addNewWishlistItem() { console.log("addNewWishlistItem"); wishlistItem.value = new WishlistItemModel(); wishlistItem.value.wishlistItemId = null; + buttonState.value = "create"; } + const submitForm = async (formEl: FormInstance | undefined) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { - WishlistService.createNewWishlistItem( userId, wishlistItem.value).then((data)=>{ + WishlistService.createNewWishlistItem( wishlistItem.value).then((data)=>{ console.log("Receiving create wishlist item data", data); if(data["data"] === null){ // TODO: create failed, handle it later }else{ wishlistItem.value = data["data"]; wishlistList.value.push(data["data"]); + buttonState.value = "edit"; } }) console.log("submit!"); @@ -220,12 +307,31 @@ const submitForm = async (formEl: FormInstance | undefined) => { }); }; -const resetForm = (formEl: FormInstance | undefined) => { - // TODO: make it delete to testing, need to change it back - // if (!formEl) return; - // formEl.resetFields(); +const updateForm = async (formEl: FormInstance | undefined) =>{ + if (!formEl) return; + await formEl.validate((valid, fields) => { + if (valid) { + WishlistService.createNewWishlistItem( wishlistItem.value).then((data)=>{ + console.log("Receiving wishlist item data", data); + if(data["data"] === null){ + // TODO: create failed, handle it later + }else{ + wishlistItem.value = data["data"]; + wishlistList.value[selectedIdx] = data["data"]; + buttonState.value = "edit"; + } + }) + console.log("submit!"); + } else { + console.log("error submit!", fields); + } + console.log(wishlistItem.value); + }); +} + +const deleteForm = async (formEl: FormInstance | undefined) => { if(wishlistItem.value.wishlistItemId !== null){ - WishlistService.deleteWishlistItem(userId, wishlistItem.value.wishlistItemId).then((data)=>{ + await WishlistService.deleteWishlistItem( wishlistItem.value.wishlistItemId).then((data)=>{ console.log("Delete wishlist item", data); if(data["data"] === null){ // TODO: delete failed or something wrong @@ -264,4 +370,14 @@ const options = Array.from({ length: 10000 }).map((_, idx) => ({ .main-card { padding: 0 0 0 20px; } +.o-zipCode { + font-size: 12px; +} +.o-owner { + font-size: 12px; +} +.item { + margin-top: 10px; + margin-right: 40px; +} </style> diff --git a/FrontendFolder/switch-room/src/models/OfferPageWishlistMatchRequestInfo.ts b/FrontendFolder/switch-room/src/models/OfferPageWishlistMatchRequestInfo.ts new file mode 100644 index 0000000000000000000000000000000000000000..763f787145abfa0443c08de8cca3c85a431bc2c9 --- /dev/null +++ b/FrontendFolder/switch-room/src/models/OfferPageWishlistMatchRequestInfo.ts @@ -0,0 +1,27 @@ +export class OfferPageWishlistMatchRequestInfo { + wishlistOwnerId: number; + wishlistId: number; + startTime: Date; + endTime: Date; + wishListOwnerName: string; + hasOffer: boolean; + zipCode: number; + + constructor(wishlistOwnerId = -1, + wishlistId = -1, + startTime = new Date(), + endTime = new Date(), + wishListOwnerName = "", + hasOffer = false, + zipCode = -1) { + this.wishlistOwnerId = wishlistOwnerId; + this.wishlistId = wishlistId; + this.startTime = startTime; + this.endTime = endTime; + this.wishListOwnerName = wishListOwnerName; + this.hasOffer = hasOffer; + this.zipCode = zipCode; + } + + +} \ No newline at end of file diff --git a/FrontendFolder/switch-room/src/models/WishlistPageOfferMatchRequestInfo.ts b/FrontendFolder/switch-room/src/models/WishlistPageOfferMatchRequestInfo.ts new file mode 100644 index 0000000000000000000000000000000000000000..471d70302d36a209df463cb0d3a2d31993ddb55f --- /dev/null +++ b/FrontendFolder/switch-room/src/models/WishlistPageOfferMatchRequestInfo.ts @@ -0,0 +1,25 @@ +export class WishlistPageOfferMatchRequestInfo { + offerOwnerId: number; + wishListId: number; + startTime: Date; + endTime: Date; + zipCode: number; + hostName: string; + + constructor(offerOwnerId =-1, + wishListId = -1, + startTime = new Date(), + endTime = new Date(), + zipCode = -1, + hostName = "" + ) { + this.offerOwnerId = offerOwnerId; + this.wishListId = wishListId; + this.startTime = startTime; + this.endTime = endTime; + this.zipCode = zipCode; + this.hostName = hostName; + } + + +} \ No newline at end of file diff --git a/FrontendFolder/switch-room/src/services/OfferPageService.ts b/FrontendFolder/switch-room/src/services/OfferPageService.ts index 618095a0a27b23b406e3e1d372c1f80cb3836a74..277f08368fd9ff2257608bf13e3625b966e3ee4f 100644 --- a/FrontendFolder/switch-room/src/services/OfferPageService.ts +++ b/FrontendFolder/switch-room/src/services/OfferPageService.ts @@ -11,8 +11,8 @@ const baseUrl = "offer"; * Get offer with userID * @param userId the current user's id */ -export async function getUserOfferInfoFromServer(userId: number) { - return serverHttpService.Get(baseUrl + "/" + userId); +export async function getUserOfferInfoFromServer() { + return serverHttpService.Get(baseUrl); } /** @@ -38,14 +38,19 @@ export function updateOffer(offerForm: OfferFormModel) { * @param userId user's id * @param offerId form id */ -export function deleteOffer(userId: number) { - const urlPath = baseUrl + "/deleteOffer/" + userId; +export function deleteOffer(userId : number) { + const urlPath = baseUrl + "/deleteOffer/"+userId; return serverHttpService.Delete(urlPath); } +export function getWishlistMatchRequestInfoList(){ + const urlPath = baseUrl + "/wishlistMatchRequestInfoList" + return serverHttpService.Get(urlPath); +} + /* Change logs: Date | Author | Description 2022-10-20 | Fangzheng Zhang | create class and init - +2022-11-03 | Fangzheng Zhang | Remove user Id in parameter because cookie is ready */ diff --git a/FrontendFolder/switch-room/src/services/WishlistService.ts b/FrontendFolder/switch-room/src/services/WishlistService.ts index 5d0451f0bb6e3779669be3567128d410e47822e0..9225343f09b617f86e87435d38ed315228368fc6 100644 --- a/FrontendFolder/switch-room/src/services/WishlistService.ts +++ b/FrontendFolder/switch-room/src/services/WishlistService.ts @@ -9,19 +9,17 @@ const baseUrl = "wishlist"; /** * This function will fetch users wishlist item list - * @param userId user's id */ -export function getUserWishlistInfo(userId: number) { - return serverHttpService.Get(baseUrl + "/" + userId); +export function getUserWishlistInfo() { + return serverHttpService.Get(baseUrl); } /** * Send new wishlistItem information to server to create new record - * @param userId user's id * @param wishlistItem new wishlistItem */ -export function createNewWishlistItem( userId: number, wishlistItem: WishlistItemModel ) { - return serverHttpService.Post(baseUrl + "/newWishlistItem/"+userId, wishlistItem); +export function createNewWishlistItem( wishlistItem: WishlistItemModel ) { + return serverHttpService.Post(baseUrl + "/newWishlistItem", wishlistItem); } /** @@ -38,20 +36,31 @@ export function updateWishlistItem(wishlistItem: WishlistItemModel) { * @param userId user's id * @param wishlistItemId wishlist Item's Id */ -export function deleteWishlistItem(userId: number, wishlistItemId: number) { +export function deleteWishlistItem(wishlistItemId: number) { const urlPath = baseUrl + "/deleteWishlistItem/" + - userId + - "?wishlistItemId=" + wishlistItemId; return serverHttpService.Delete(urlPath); } +export function getOfferMatchList(wishlistItemId: number){ + const urlPath = baseUrl + "/loadOfferMatchList/"+wishlistItemId; + return serverHttpService.Get(urlPath); +} + +export function loadMatchOfferNumbersFor(wishlistItemList: Array<WishlistItemModel>){ + let wishlistIdList : Array<number>= []; + wishlistItemList.forEach((wishlistItem) => { + wishlistIdList.push(wishlistItem.wishlistItemId); + }) + const urlPath = baseUrl + "/loadOfferMatchCount"; + return serverHttpService.Post(urlPath, wishlistIdList); +} /* Change logs: Date | Author | Description 2022-10-20 | Fangzheng Zhang | create class and init - +2022-11-05 | Fangzheng Zhang | Add loadMatchOfferNumbersFor and getOfferMatchList to fetch match data */