diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/MatchedOfferController.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/MatchedOfferController.java new file mode 100644 index 0000000000000000000000000000000000000000..bede6a5b3582fe55bae9dc9970565ceda78f2872 --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/MatchedOfferController.java @@ -0,0 +1,59 @@ +package vt.CS5934.SwitchRoom.controllers; + +import org.slf4j.Logger; +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.ResponseModel; +import vt.CS5934.SwitchRoom.models.UserOfferModel; +import vt.CS5934.SwitchRoom.services.OfferPageService; +import vt.CS5934.SwitchRoom.services.WishlistPageService; + +/** + * The "@MatchedController" made the class into rest handle class + * The "@RequestMapping("matched")" on the class level make it only react to url ".../example/..." + */ +@CrossOrigin( + allowCredentials = "true", + origins = {"http://localhost:8080/"} +) +@RestController +@RequestMapping("matchedOffer") +public class MatchedOfferController { + + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + OfferPageService offerPageService; + + /** + * You can use logger.[trace,debug,info,warn,error]("messages") to log into file + */ + private final Logger logger = LoggerFactory.getLogger(UserController.class); + + /** + * This function will handle the post function and change the JSON body into data class + */ + @GetMapping("/{offerId}") + public ResponseModel getOffer(@PathVariable long offerId) { + logger.info("You reached the getOffer() function."); + System.out.println(offerId); + try{ + UserOfferModel offer = offerPageService.getUserOfferInfo(offerId); +// List<MatchedWishlistRecordModel> offerNotifications = matchedWishlistRecordService.getOfferListWithIDFromDB(userId); +// List<ExampleModel> exampleModels = exampleService.getAllExampleModelsFromDB(); + return new ResponseModel( + "This this a offer String response", + HttpStatus.OK, + offer); + }catch (Exception e){ + return new ResponseModel( + "Error occur on get All ExampleModels, Error info is: " + e, + HttpStatus.OK, + null); + } + } +} \ No newline at end of file diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/MatchedWishListController.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/MatchedWishListController.java new file mode 100644 index 0000000000000000000000000000000000000000..ed7cdec427db88bddd53d6e26e252d540f32546c --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/MatchedWishListController.java @@ -0,0 +1,57 @@ +package vt.CS5934.SwitchRoom.controllers; + +import org.slf4j.Logger; +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.ResponseModel; +import vt.CS5934.SwitchRoom.models.WishlistItemModel; +import vt.CS5934.SwitchRoom.services.WishlistPageService; + + +/** + * The "@MatchedController" made the class into rest handle class + * The "@RequestMapping("matched")" on the class level make it only react to url ".../example/..." + */ +@CrossOrigin( + allowCredentials = "true", + origins = {"http://localhost:8080/"} +) +@RestController +@RequestMapping("matchedWishList") +public class MatchedWishListController { + + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + WishlistPageService wishlistPageService; + + /** + * You can use logger.[trace,debug,info,warn,error]("messages") to log into file + */ + private final Logger logger = LoggerFactory.getLogger(UserController.class); + + /** + * This function will handle the post function and change the JSON body into data class + */ + @GetMapping("/{wishlistId}") + public ResponseModel getWishList(@PathVariable long wishlistId) { + logger.info("You reached the getWishList() function."); + System.out.println(wishlistId); + try{ + WishlistItemModel wishlist = wishlistPageService.getWishlistItemInfo(wishlistId); + return new ResponseModel( + "This this a offer String response", + HttpStatus.OK, + wishlist); + }catch (Exception e){ + return new ResponseModel( + "Error occur on get All ExampleModels, Error info is: " + e, + HttpStatus.OK, + null); + } + } +} diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/NotificationController.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/NotificationController.java new file mode 100644 index 0000000000000000000000000000000000000000..7080bc3e0e6f6aee73a805d845c6ddc34fbc3de8 --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/controllers/NotificationController.java @@ -0,0 +1,105 @@ +package vt.CS5934.SwitchRoom.controllers; + +import org.slf4j.Logger; +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.*; +import vt.CS5934.SwitchRoom.services.DealWithWishlist; +import vt.CS5934.SwitchRoom.services.MatchedWishlistRecordService; +import vt.CS5934.SwitchRoom.services.OfferWishlistLookUpService; +import vt.CS5934.SwitchRoom.services.UserService; + +import java.util.List; + + +/** + * The "@RestController" made the class into rest handle class + * The "@RequestMapping("example")" on the class level make it only react to url ".../example/..." + */ +@CrossOrigin( + allowCredentials = "true", + origins = {"http://localhost:8080/"} +) +@RestController +@RequestMapping("notification") +public class NotificationController { + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + MatchedWishlistRecordService matchedWishlistRecordService; + + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + OfferWishlistLookUpService offerWishlistLookUpService; + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + DealWithWishlist dealWithWishlist; + + /** + * You can use logger.[trace,debug,info,warn,error]("messages") to log into file + */ + private final Logger logger = LoggerFactory.getLogger(UserController.class); + + /** + * This function will handle the post function and change the JSON body into data class + */ + @CrossOrigin + @GetMapping("/{userId}") + public ResponseModel getNotification(@PathVariable long userId) { + logger.info("You reached the getNotification() function."); +// System.out.println(userId); + try{ + List<MatchedWishlistRecordModel> offerNotifications = matchedWishlistRecordService.getOfferListWithIDFromDB(userId); +// System.out.println(offerNotifications); +// List<ExampleModel> exampleModels = exampleService.getAllExampleModelsFromDB(); + return new ResponseModel( + "This this a notification String response", + HttpStatus.OK, + offerNotifications); + }catch (Exception e){ + return new ResponseModel( + "Error occur on get All ExampleModels, Error info is: " + e, + HttpStatus.OK, + null); + } + } + + /** + * This function will handle the post function and change the JSON body into data class + */ + @CrossOrigin( + allowCredentials = "true", + origins = {"http://localhost:8080/"} + ) + @GetMapping("/wish/{userId}") + public ResponseModel getNotificationwish(@PathVariable long userId) { + logger.info("You reached the getNotificationwish() function."); +// System.out.println(userId); + try{ + List<UserOfferWishlistLookUpModel> lookup = offerWishlistLookUpService.getOfferWishlistLookUpWithIDFromDB(userId); + System.out.println(lookup); + List<MatchedWishlistRecordModel> wishlists = dealWithWishlist.getMatchedWishlist(lookup); +// List<MatchedWishlistRecordModel> offerNotifications = matchedWishlistRecordService.getOfferListWithIDFromDB(userId); +// List<ExampleModel> exampleModels = exampleService.getAllExampleModelsFromDB(); + return new ResponseModel( + "This this a notification String response", + HttpStatus.OK, + wishlists); + }catch (Exception e){ + return new ResponseModel( + "Error occur on get All ExampleModels, Error info is: " + e, + HttpStatus.OK, + null); + } + } +} 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 a299f79b0d3f7a89e4c8428d01c4f3ad721a5061..e9ef530a764129d691d31f707e55f231040cd650 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 @@ -7,7 +7,21 @@ import vt.CS5934.SwitchRoom.models.MatchedWishlistRecordModel; import java.util.List; public interface MatchedWishlistRecordRepository extends JpaRepository<MatchedWishlistRecordModel, MatchedRecordIdModel> { + /** + * The function name is the SQL query: + * findByIdAndName(long inputId, String inputName) == "SELETE * FROM table WHERE Id==inputId" AND name == inputName; + * This is an example of how to declare a SQL command, those will be use in service class + * @param offerId the id in table you are looking for + * @return ExampleModel object + */ List<MatchedWishlistRecordModel> findAllByOfferId(Long offerId); + /** + * The function name is the SQL query: + * findByIdAndName(long inputId, String inputName) == "SELETE * FROM table WHERE Id==inputId" AND name == inputName; + * This is an example of how to declare a SQL command, those will be use in service class + * @param wishlistItemId the id in table you are looking for + * @return ExampleModel object + */ List<MatchedWishlistRecordModel> findAllByWishlistItemId(Long wishlistItemId); void deleteAllByOfferId(Long offerId); diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/DealWithWishlist.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/DealWithWishlist.java new file mode 100644 index 0000000000000000000000000000000000000000..8c5c76170a5541dc20c6b5c3ea2ecc266615f36d --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/DealWithWishlist.java @@ -0,0 +1,37 @@ +package vt.CS5934.SwitchRoom.services; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import vt.CS5934.SwitchRoom.models.MatchedWishlistRecordModel; +import vt.CS5934.SwitchRoom.models.UserOfferWishlistLookUpModel; +import vt.CS5934.SwitchRoom.repositories.MatchedWishlistRecordRepository; +import vt.CS5934.SwitchRoom.repositories.UserOfferWishlistLookUpRepository; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class DealWithWishlist { + + /** + * You can use logger.[trace,debug,info,warn,error]("messages") to log into file + */ + private final Logger logger = LoggerFactory.getLogger(ExampleService.class); + + @Autowired + MatchedWishlistRecordRepository matchedWishlistRecordRepository; + + public List<MatchedWishlistRecordModel> getMatchedWishlist(List<UserOfferWishlistLookUpModel> list) { + logger.info("Reached get finalAns"); + List<MatchedWishlistRecordModel> finalAns = new ArrayList<>(); + for(int i = 0; i < list.size(); i++) { + System.out.println(list.get(i).getWishlistItemId()); + List<MatchedWishlistRecordModel> ans = matchedWishlistRecordRepository.findByWishlistItemId(list.get(i).getWishlistItemId()); + System.out.println(ans); + finalAns.addAll(ans); + } + return finalAns; + } +} diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/MatchedWishlistRecordService.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/MatchedWishlistRecordService.java new file mode 100644 index 0000000000000000000000000000000000000000..8fa7e827ffcfbbab3ff94a319c688607abf1a15c --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/MatchedWishlistRecordService.java @@ -0,0 +1,31 @@ +package vt.CS5934.SwitchRoom.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import vt.CS5934.SwitchRoom.models.MatchedWishlistRecordModel; +import vt.CS5934.SwitchRoom.repositories.MatchedWishlistRecordRepository; + +import java.util.List; + +@Service +public class MatchedWishlistRecordService { + + /** + * You can use logger.[trace,debug,info,warn,error]("messages") to log into file + */ + private final Logger logger = LoggerFactory.getLogger(MatchedWishlistRecordService.class); + + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + MatchedWishlistRecordRepository matchedWishlistRecordRepository; + + public List<MatchedWishlistRecordModel> getOfferListWithIDFromDB(long id){ + logger.info("Reached getOfferListIDFromDB()"); + return matchedWishlistRecordRepository.findByOfferId(id); + } +} diff --git a/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferWishlistLookUpService.java b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferWishlistLookUpService.java new file mode 100644 index 0000000000000000000000000000000000000000..44bbe0768a9fe9e1cac07245b587e84c8ac6b1f4 --- /dev/null +++ b/BackendFolder/SwitchRoom/src/main/java/vt/CS5934/SwitchRoom/services/OfferWishlistLookUpService.java @@ -0,0 +1,34 @@ +package vt.CS5934.SwitchRoom.services; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import vt.CS5934.SwitchRoom.models.ExampleModel; +import vt.CS5934.SwitchRoom.models.MatchedWishlistRecordModel; +import vt.CS5934.SwitchRoom.models.UserOfferWishlistLookUpModel; +import vt.CS5934.SwitchRoom.repositories.MatchedWishlistRecordRepository; +import vt.CS5934.SwitchRoom.repositories.UserOfferWishlistLookUpRepository; + +import java.util.*; + +@Service +public class OfferWishlistLookUpService { + + /** + * You can use logger.[trace,debug,info,warn,error]("messages") to log into file + */ + private final Logger logger = LoggerFactory.getLogger(ExampleService.class); + + /** + * Autowired is a Spring feature that it will create or looking for the existing object in memory. + * It usually uses on Repository class, Service class, or some globe object in the class. + */ + @Autowired + UserOfferWishlistLookUpRepository userOfferWishlistLookUpRepository; + + public List<UserOfferWishlistLookUpModel> getOfferWishlistLookUpWithIDFromDB(long id){ + logger.info("Reached getWishlistLookUpWithIDFromDB()"); + return userOfferWishlistLookUpRepository.findAllByUserId(id); + } +} diff --git a/FrontendFolder/switch-room/package-lock.json b/FrontendFolder/switch-room/package-lock.json index 4bd21bf6defaa8ab56742b16768cfd325484d12b..c33372e1981d042a399da2b6906faf730dbc37d7 100644 --- a/FrontendFolder/switch-room/package-lock.json +++ b/FrontendFolder/switch-room/package-lock.json @@ -14,6 +14,7 @@ "@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/vue-fontawesome": "^3.0.1", "cookie-parser": "^1.4.6", + "cors": "^2.8.5", "element-plus": "^2.2.18", "vue": "^3.2.13", "vue-router": "^4.0.3", @@ -21,6 +22,7 @@ }, "devDependencies": { "@types/cookie-parser": "^1.4.3", + "@types/cors": "^2.8.12", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", "@vue/cli-plugin-router": "~5.0.0", @@ -857,6 +859,12 @@ "@types/express": "*" } }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.4.6", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", @@ -3091,6 +3099,18 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", @@ -6724,7 +6744,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9320,7 +9339,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, "engines": { "node": ">= 0.8" } @@ -10879,6 +10897,12 @@ "@types/express": "*" } }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "@types/eslint": { "version": "8.4.6", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", @@ -12566,6 +12590,15 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", @@ -15266,8 +15299,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { "version": "1.12.2", @@ -17138,8 +17170,7 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "vue": { "version": "3.2.41", diff --git a/FrontendFolder/switch-room/package.json b/FrontendFolder/switch-room/package.json index bab7489723bd9f72e5ede3a9fabf74b71294ccac..c89c1d112c44eeca159474caac5bbf0ed794eeee 100644 --- a/FrontendFolder/switch-room/package.json +++ b/FrontendFolder/switch-room/package.json @@ -14,6 +14,7 @@ "@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/vue-fontawesome": "^3.0.1", "cookie-parser": "^1.4.6", + "cors": "^2.8.5", "element-plus": "^2.2.18", "vue": "^3.2.13", "vue-router": "^4.0.3", @@ -21,6 +22,7 @@ }, "devDependencies": { "@types/cookie-parser": "^1.4.3", + "@types/cors": "^2.8.12", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", "@vue/cli-plugin-router": "~5.0.0", diff --git a/FrontendFolder/switch-room/src/components/AppHeader.vue b/FrontendFolder/switch-room/src/components/AppHeader.vue index b012f07c5a4399df33b7a25cc77179a93b43a48c..cd6b1832051d60f740cda68882b3f88e995db012 100644 --- a/FrontendFolder/switch-room/src/components/AppHeader.vue +++ b/FrontendFolder/switch-room/src/components/AppHeader.vue @@ -15,6 +15,7 @@ <el-menu-item index="3" v-on:click="redirect('/wishlist-page')">Wish List</el-menu-item> <el-menu-item index="4" v-on:click="redirect('/flight')">Flight Ticket</el-menu-item> <el-menu-item index="5" v-on:click="redirect('/profile')">Profile</el-menu-item> + <notification></notification> <el-menu-item index="6" class="dock-right" @click="hanldeLogOut()">Log Out</el-menu-item> </el-menu> </template> @@ -22,7 +23,11 @@ <script lang="ts"> import { defineComponent } from "vue"; import { mapActions, mapGetters } from "vuex"; +import Notification from "@/components/Notification.vue"; +import { OfferNotification } from "@/models/OfferNotification"; export default defineComponent({ + components: { Notification }, + props: ["offers"], data() { return { hasToken: document.cookie.length > 0 @@ -48,6 +53,6 @@ export default defineComponent({ <style scoped> .el-menu-demo > .el-menu-item.dock-right { - margin-left: auto + margin-left: auto; } </style> diff --git a/FrontendFolder/switch-room/src/components/MainPage.vue b/FrontendFolder/switch-room/src/components/MainPage.vue index 2d69366a732961d499c9203881a7cbac9033bee8..a105bd70bdb1b20945010f443c43fd66b4a10020 100644 --- a/FrontendFolder/switch-room/src/components/MainPage.vue +++ b/FrontendFolder/switch-room/src/components/MainPage.vue @@ -27,25 +27,25 @@ Username </label> <input - id="user-name" - v-model="username" - class="form-content" - type="text" - name="username" - autocomplete="on" - required + id="user-name" + v-model="username" + class="form-content" + type="text" + name="username" + autocomplete="on" + required /> <div class="form-border"></div> <label for="user-password" style="padding-top: 22px" - > Password + > Password </label> <input - id="user-password" - v-model="password" - class="form-content" - type="password" - name="password" - required + id="user-password" + v-model="password" + class="form-content" + type="password" + name="password" + required /> <div class="form-border"></div> <a href="#"> @@ -66,7 +66,7 @@ <script lang="ts"> import { defineComponent } from "vue"; import { mapActions, mapGetters } from "vuex"; -import {checkLoginSession} from "../services/UserService"; +import { checkLoginSession } from "../services/UserService"; export default defineComponent({ data() { @@ -85,14 +85,13 @@ export default defineComponent({ actionLoginApi: "loginApi", }), async handleCreated() { - await checkLoginSession() - .then((result) => { + await checkLoginSession().then((result) => { if (result.status == "OK") { - this.$router.push({name: 'LoginMainPage'}); + this.$router.push({ name: "LoginMainPage" }); } else { - this.$router.push({name: 'home'}) + this.$router.push({ name: "home" }); } - }) + }); }, async handleLogin() { const payload = { @@ -100,17 +99,15 @@ export default defineComponent({ password: this.password, }; await this.actionLoginApi(payload); - if (this.getLoginStatus){ - this.$router.push({name: 'LoginMainPage'}); + if (this.getLoginStatus) { + this.$router.push({ name: "LoginMainPage" }); } }, }, - created: function(){ - this.handleCreated() - } + created: function () { + this.handleCreated(); + }, }); - - </script> <style scoped> diff --git a/FrontendFolder/switch-room/src/components/MatchOffer.vue b/FrontendFolder/switch-room/src/components/MatchOffer.vue new file mode 100644 index 0000000000000000000000000000000000000000..e9bbdee7837e91396bd1e9239099e6cf65ed75c4 --- /dev/null +++ b/FrontendFolder/switch-room/src/components/MatchOffer.vue @@ -0,0 +1,46 @@ +<template> + <div class="offerSide"> + <div class="card"> + <div class="container"> + <h4><b>Matched Offer Information</b></h4> + <p>Space Located City: {{ offer.spaceLocateCity }}</p> + <p>Space Located State: {{ offer.state }}</p> + <p>Available Time start: {{ offer.availableTimeStart }}</p> + <p>Available Time end: {{ offer.availableTimeEnd }}</p> + <p>Max People: {{ offer.maxNumberOfPeople }}</p> + <p v-if="offer.offering">It is offering now</p> + </div> + </div> + </div> +</template> + +<script setup lang="ts"> +import { defineProps } from "vue"; +import { OfferFormModel } from "@/models/OfferFormModel"; + +const props = defineProps<{ + offer: OfferFormModel; +}>(); +</script> + +<style scoped> +.offerSide { + display: flex; + justify-content: center; + align-items: center; +} +.card { + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); + transition: 0.3s; + width: 40%; + text-align: center; +} + +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); +} + +.container { + padding: 2px 16px; +} +</style> diff --git a/FrontendFolder/switch-room/src/components/MatchWishList.vue b/FrontendFolder/switch-room/src/components/MatchWishList.vue new file mode 100644 index 0000000000000000000000000000000000000000..2af628d7c9e746f9e2936e9a8bfe67723a3513ec --- /dev/null +++ b/FrontendFolder/switch-room/src/components/MatchWishList.vue @@ -0,0 +1,45 @@ +<template> + <div class="wishlistSide"> + <div class="card"> + <div class="container"> + <h4><b>Matched required space Information</b></h4> + <p>required city: {{ wishlist.cityName }}</p> + <p>required state: {{ wishlist.state }}</p> + <p>required start time: {{ wishlist.startTime }}</p> + <p>required end time: {{ wishlist.endTime }}</p> + <p>required details: {{ wishlist.details }}</p> + </div> + </div> + </div> +</template> + +<script setup lang="ts"> +import { defineProps } from "vue"; +import { WishlistItemModel } from "@/models/WishlistItemModel"; + +const props = defineProps<{ + wishlist: WishlistItemModel; +}>(); +</script> + +<style scoped> +.wishlistSide { + display: flex; + justify-content: center; + align-items: center; +} +.card { + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); + transition: 0.3s; + width: 40%; + text-align: center; +} + +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); +} + +.container { + padding: 2px 16px; +} +</style> diff --git a/FrontendFolder/switch-room/src/components/Notification.vue b/FrontendFolder/switch-room/src/components/Notification.vue new file mode 100644 index 0000000000000000000000000000000000000000..cd25dd5532c25d51e510457281c44d1884e29393 --- /dev/null +++ b/FrontendFolder/switch-room/src/components/Notification.vue @@ -0,0 +1,92 @@ +<template> + <el-dropdown class="notification"> + <el-button type="primary"> + <font-awesome-icon icon="fa-solid fa-envelope" /> + Notification<el-icon class="el-icon--right"><arrow-down /></el-icon> + </el-button> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item v-for="offer in offers" :key="offer.offerId"> + <router-link + :to=" + '/matched-result/' + offer.offerId + '/' + offer.wishlistItemId + " + > + You have a offer matched (click to check details) + </router-link> + </el-dropdown-item> + <el-dropdown-item v-for="offer in offers2" :key="offer.offerId"> + <router-link + :to=" + '/matched-result/' + offer.offerId + '/' + offer.wishlistItemId + " + > + You have a wishlist matched (click to check details) + </router-link> + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> +</template> + +<script setup lang="ts"> +import { ref, watch } from "vue"; +import { OfferNotification } from "@/models/OfferNotification"; +import * as NotificationService from "@/services/NotificationService"; +import { useRoute } from "vue-router"; +import { onMounted } from "vue"; + +const route = useRoute(); + +function getCookie(userId: string) { + const value = `; ${document.cookie}`; + const parts: string[] = value.split(`; ${userId}=`); + if (parts.length === 2) return parts?.pop()?.split(";").shift(); +} + +const offers = ref([] as OfferNotification[]); +const offers2 = ref([] as OfferNotification[]); +async function fetchNotification(userId: number) { + const response = await NotificationService.getNotificationFromServerWithID( + userId + ); + // const response2 = + // await NotificationService.getNotificationwishFromServerWithID(userId); + // console.log(response2); + offers.value = response.data; + // offers2.value = response2.data; +} + +async function fetchNotificationwish(userId: number) { + const response2 = + await NotificationService.getNotificationwishFromServerWithID(userId); + offers2.value = response2.data; +} + +watch( + () => route.name, + (values) => { + const userIdString: string = getCookie("userId"); + let userIdNumber = +userIdString; + fetchNotification(userIdNumber); + fetchNotificationwish(userIdNumber); + }, + { immediate: true } +); +</script> + +<style scoped> +.notification { + margin: auto; + justify-content: space-between; +} +.example-showcase .el-dropdown + .el-dropdown { + margin-left: 15px; +} +.example-showcase .el-dropdown-link { + cursor: pointer; + color: var(--el-color-primary); + display: flex; + align-items: center; +} +</style> diff --git a/FrontendFolder/switch-room/src/components/WishlistPage.vue b/FrontendFolder/switch-room/src/components/WishlistPage.vue index b3ebe41cba78ab444d82d342a52d2f0e8d940f5c..19ccd9ea47266fede251f9effd8e2e23c3c409d3 100644 --- a/FrontendFolder/switch-room/src/components/WishlistPage.vue +++ b/FrontendFolder/switch-room/src/components/WishlistPage.vue @@ -152,7 +152,6 @@ </el-container> </div> </el-card> - </el-col> <el-col :span="2"><div class="grid-content ep-bg-purple" /></el-col> </el-row> @@ -320,7 +319,7 @@ const updateForm = async (formEl: FormInstance | undefined) =>{ wishlistList.value[selectedIdx] = data["data"]; buttonState.value = "edit"; } - }) + ) console.log("submit!"); } else { console.log("error submit!", fields); diff --git a/FrontendFolder/switch-room/src/models/OfferNotification.ts b/FrontendFolder/switch-room/src/models/OfferNotification.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9af3a6f2485d4a6be6acdc012c479f77e8cf3df --- /dev/null +++ b/FrontendFolder/switch-room/src/models/OfferNotification.ts @@ -0,0 +1,21 @@ +export class OfferNotification { + public offerId: number; + public wishlistItemId: number; + public modifyDate: Date; + public offerResult: number; + public wishlistResult: number; + + constructor( + offerId = -1, + wishlistItemId = -1, + modifyDate = new Date(), + offerResult = -1, + wishlistResult = -1 + ) { + this.offerId = offerId; + this.wishlistItemId = wishlistItemId; + this.modifyDate = modifyDate; + this.offerResult = offerResult; + this.wishlistResult = wishlistResult; + } +} diff --git a/FrontendFolder/switch-room/src/router/index.ts b/FrontendFolder/switch-room/src/router/index.ts index e11c2b547c02aaff15880f69966d3fadc391ebb4..f88e669f908ffcde73ba872fc8522e4a8dafb1a6 100644 --- a/FrontendFolder/switch-room/src/router/index.ts +++ b/FrontendFolder/switch-room/src/router/index.ts @@ -3,6 +3,7 @@ import HomeView from "../views/HomeView.vue"; import RegisterView from "../views/RegisterView.vue"; import ResetPasswordView from "../views/ResetPasswordView.vue"; import ProfileView from "../views/ProfileView.vue"; +import MatchedView from "../views/MatchedView.vue"; const routes: Array<RouteRecordRaw> = [ { @@ -79,9 +80,14 @@ const routes: Array<RouteRecordRaw> = [ requiresAuth: true, hideHeader: false, }, - component: () => - import("../views/LoginMainPageView.vue"), - } + component: () => import("../views/LoginMainPageView.vue"), + }, + + { + path: "/matched-result/:offerId/:wishlistId", + name: "MatchResultPage", + component: MatchedView, + }, ]; const router = createRouter({ @@ -90,15 +96,15 @@ const router = createRouter({ }); router.beforeEach((to, from, next) => { - if (to.matched.some(record => record.meta.requiresAuth)) { + if (to.matched.some((record) => record.meta.requiresAuth)) { if (!document.cookie) { - next({ name: 'home' }) + next({ name: "home" }); } else { - next() + next(); } } else { - next() + next(); } -}) +}); export default router; diff --git a/FrontendFolder/switch-room/src/services/Constans.ts b/FrontendFolder/switch-room/src/services/Constans.ts index 62c819fe24459fc3d7cd53959d66103611092c88..b032e5f6c56fa6f34c0ece6f867cf24e627fef56 100644 --- a/FrontendFolder/switch-room/src/services/Constans.ts +++ b/FrontendFolder/switch-room/src/services/Constans.ts @@ -3,14 +3,69 @@ */ const SEVER_IP = location.hostname; + const SERVER_PORT = 8081; const Server_URL = location.protocol + "//" + SEVER_IP + ":" + SERVER_PORT + "/"; -const USA_STATE_INITAL_LIST = ['AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'GU', 'HI', - 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', - 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'VI', - 'WA', 'WV', 'WI', 'WY'] +const USA_STATE_INITAL_LIST = [ + "AL", + "AK", + "AS", + "AZ", + "AR", + "CA", + "CO", + "CT", + "DE", + "DC", + "FL", + "GA", + "GU", + "HI", + "ID", + "IL", + "IN", + "IA", + "KS", + "KY", + "LA", + "ME", + "MD", + "MA", + "MI", + "MN", + "MS", + "MO", + "MT", + "NE", + "NV", + "NH", + "NJ", + "NM", + "NY", + "NC", + "ND", + "MP", + "OH", + "OK", + "OR", + "PA", + "PR", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VT", + "VA", + "VI", + "WA", + "WV", + "WI", + "WY", +]; export { SEVER_IP, SERVER_PORT, Server_URL, USA_STATE_INITAL_LIST }; diff --git a/FrontendFolder/switch-room/src/services/FetchOfferService.ts b/FrontendFolder/switch-room/src/services/FetchOfferService.ts new file mode 100644 index 0000000000000000000000000000000000000000..428a2b0629103b8102e23538d58fa1511e1d6aed --- /dev/null +++ b/FrontendFolder/switch-room/src/services/FetchOfferService.ts @@ -0,0 +1,10 @@ +import * as serverHttpService from "./ServerHttpService"; + +const baseUrl = "matchedOffer"; + +function getOffersFromServerWithID(offerId: number) { + const urlPath = "/" + offerId; + return serverHttpService.Get(baseUrl + urlPath); +} + +export { getOffersFromServerWithID }; diff --git a/FrontendFolder/switch-room/src/services/FetchWishListService.ts b/FrontendFolder/switch-room/src/services/FetchWishListService.ts new file mode 100644 index 0000000000000000000000000000000000000000..db9eda30612cdafde08ce653b89a00d58fe8d8ec --- /dev/null +++ b/FrontendFolder/switch-room/src/services/FetchWishListService.ts @@ -0,0 +1,10 @@ +import * as serverHttpService from "./ServerHttpService"; + +const baseUrl = "matchedWishList"; + +function getWishListFromServerWithID(wishListId: number) { + const urlPath = "/" + wishListId; + return serverHttpService.Get(baseUrl + urlPath); +} + +export { getWishListFromServerWithID }; diff --git a/FrontendFolder/switch-room/src/services/NotificationService.ts b/FrontendFolder/switch-room/src/services/NotificationService.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa8bbace6cac91779a61a09415bf183c9bf28f19 --- /dev/null +++ b/FrontendFolder/switch-room/src/services/NotificationService.ts @@ -0,0 +1,15 @@ +import * as serverHttpService from "./ServerHttpService"; + +const baseUrl = "notification"; + +function getNotificationFromServerWithID(userId: number) { + const urlPath = "/" + userId; + return serverHttpService.Get(baseUrl + urlPath); +} + +function getNotificationwishFromServerWithID(userId: number) { + const urlPath = "/wish/" + userId; + return serverHttpService.Get(baseUrl + urlPath); +} + +export { getNotificationFromServerWithID, getNotificationwishFromServerWithID }; diff --git a/FrontendFolder/switch-room/src/store/modules/auth.ts b/FrontendFolder/switch-room/src/store/modules/auth.ts index 85bc4c1ae52381bd0bec95b8fbaafcffd0eea780..711f290c4f4e6e40c6bf40ade9f7134a98d0ac95 100644 --- a/FrontendFolder/switch-room/src/store/modules/auth.ts +++ b/FrontendFolder/switch-room/src/store/modules/auth.ts @@ -1,42 +1,44 @@ import * as UserService from "../../services/UserService"; const state = () => ({ - loginStatus: false, + loginStatus: false, }); const getters = { - getLoginStatus(state: any) { - return state.loginStatus; - }, - }; + getLoginStatus(state: any) { + return state.loginStatus; + }, +}; const actions = { - async loginApi({ commit }: any, payload: any) { - const response = await UserService.loginUser(JSON.stringify(payload)) - .catch((error) => alert(error)); - if (response.status == "OK") { - commit("setLoginStatus", true); - } else { - alert(response.message) - } - }, - logOutApi({ commit }: any) { - // todo: clear session in backend - console.log("logOut") - commit("setLoginStatus", false); + async loginApi({ commit }: any, payload: any) { + const response = await UserService.loginUser(JSON.stringify(payload)).catch( + (error) => alert(error) + ); + if (response.status == "OK") { + const userId = response.data.userId; + commit("setLoginStatus", true); + } else { + alert(response.message); } + }, + logOutApi({ commit }: any) { + // todo: clear session in backend + console.log("logOut"); + commit("setLoginStatus", false); + }, }; const mutations = { - setLoginStatus(state: any, data: any) { - state.loginStatus = data; - }, - }; + setLoginStatus(state: any, data: any) { + state.loginStatus = data; + }, +}; export default { - namespaced: true, - state, - getters, - actions, - mutations, -}; \ No newline at end of file + namespaced: true, + state, + getters, + actions, + mutations, +}; diff --git a/FrontendFolder/switch-room/src/views/LoginMainPageView.vue b/FrontendFolder/switch-room/src/views/LoginMainPageView.vue index 548ebc671b1c0edc7ee8441cd36ad0d32d103a87..1502ffb97752765dfd2b86edb25bd0e423552964 100644 --- a/FrontendFolder/switch-room/src/views/LoginMainPageView.vue +++ b/FrontendFolder/switch-room/src/views/LoginMainPageView.vue @@ -1,8 +1,40 @@ <template> - <main-page></main-page> + <main-page></main-page> </template> <script setup lang="ts"> import MainPage from "@/components/LoginMainPage.vue"; +import AppHeader from "@/components/AppHeader.vue"; +import { watch } from "vue"; +import { useRoute } from "vue-router"; +const route = useRoute(); +import { ref } from "vue"; +import { OfferNotification } from "@/models/OfferNotification"; +import * as NotificationService from "@/services/NotificationService"; + +// function getCookie(userId: string) { +// const value = `; ${document.cookie}`; +// const parts: string[] = value.split(`; ${userId}=`); +// if (parts.length === 2) return parts?.pop()?.split(";").shift(); +// } +// +// const offers = ref([] as OfferNotification[]); +// async function fetchNotification(userId: number) { +// const response = await NotificationService.getNotificationFromServerWithID( +// userId +// ); +// console.log(response); +// offers.value = response.data; +// } +// +// watch( +// () => route.name, +// (values) => { +// const userIdString: string = getCookie("userId"); +// let userIdNumber = +userIdString; +// console.log(userIdNumber); +// fetchNotification(userIdNumber); +// }, +// { immediate: true } +// ); </script> - \ No newline at end of file diff --git a/FrontendFolder/switch-room/src/views/MatchedView.vue b/FrontendFolder/switch-room/src/views/MatchedView.vue new file mode 100644 index 0000000000000000000000000000000000000000..641b85322d138e981295efb15fd422ca156c2742 --- /dev/null +++ b/FrontendFolder/switch-room/src/views/MatchedView.vue @@ -0,0 +1,159 @@ +<template> + <div class="match-view"> + <p>This is the matched result page</p> + <match-offer :offer="offer"></match-offer> + <match-wish-list :wishlist="wishlist"></match-wish-list> + <button>Sign Agreement Documentation</button> + <button>It is not suitable</button> + </div> +</template> + +<script setup lang="ts"> +import { ref, watch } from "vue"; +import { useRoute } from "vue-router"; +import * as FetchOfferService from "@/services/FetchOfferService"; +import * as FetchWishListService from "@/services/FetchWishListService"; +import { OfferFormModel } from "@/models/OfferFormModel"; +import { WishlistItemModel } from "@/models/WishlistItemModel"; +import MatchOffer from "@/components/MatchOffer.vue"; +import MatchWishList from "@/components/MatchWishList.vue"; + +const route = useRoute(); +const offer = ref(OfferFormModel); +const wishlist = ref(WishlistItemModel); + +async function fetchOffer(offerId: number) { + const response = await FetchOfferService.getOffersFromServerWithID(offerId); + console.log(response.data); + offer.value = response.data; +} + +async function fetchWishList(wishlistId: number) { + const response = await FetchWishListService.getWishListFromServerWithID( + wishlistId + ); + console.log(response.data); + wishlist.value = response.data; +} + +watch( + () => route.name, + (values) => { + const offerIdName = route.params.offerId; + const offerIdNumber = +offerIdName; + const wishlistIdName = route.params.wishlistId; + const wishlistIdNumber = +wishlistIdName; + fetchOffer(offerIdNumber); + fetchWishList(wishlistIdNumber); + }, + { immediate: true } +); +</script> + +<style scoped> +.match-view { + display: block; + text-align: center; +} + +.button1 { + margin-top: 2%; + margin-left: 2%; +} + +button, +button::after { + margin-top: 2%; + margin-left: 2%; + width: 300px; + height: 86px; + font-size: 36px; + font-family: "Bebas Neue", cursive; + background: #1e5be6; + border: 0; + color: #fff; + letter-spacing: 3px; + line-height: 88px; + box-shadow: 6px 0px 0px #00e6f6; + outline: transparent; + position: relative; +} + +button::after { + --slice-0: inset(50% 50% 50% 50%); + --slice-1: inset(80% -6px 0 0); + --slice-2: inset(50% -6px 30% 0); + --slice-3: inset(10% -6px 85% 0); + --slice-4: inset(40% -6px 43% 0); + --slice-5: inset(80% -6px 5% 0); + + content: "AVAILABLE NOW"; + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient( + 45deg, + transparent 3%, + #00e6f6 3%, + #00e6f6 5%, + #ff013c 5% + ); + text-shadow: -3px -3px 0px #f8f005, 3px 3px 0px #00e6f6; + clip-path: var(--slice-0); +} + +button:hover::after { + animation: 1s glitch; + animation-timing-function: steps(2, end); +} + +@keyframes glitch { + 0% { + clip-path: var(--slice-1); + transform: translate(-20px, -10px); + } + 10% { + clip-path: var(--slice-3); + transform: translate(10px, 10px); + } + 20% { + clip-path: var(--slice-1); + transform: translate(-10px, 10px); + } + 30% { + clip-path: var(--slice-3); + transform: translate(0px, 5px); + } + 40% { + clip-path: var(--slice-2); + transform: translate(-5px, 0px); + } + 50% { + clip-path: var(--slice-3); + transform: translate(5px, 0px); + } + 60% { + clip-path: var(--slice-4); + transform: translate(5px, 10px); + } + 70% { + clip-path: var(--slice-2); + transform: translate(-10px, 10px); + } + 80% { + clip-path: var(--slice-5); + transform: translate(20px, -10px); + } + 90% { + clip-path: var(--slice-1); + transform: translate(-10px, 0px); + } + 100% { + clip-path: var(--slice-1); + transform: translate(0); + } +} +</style>