aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--start.bat9
-rw-r--r--ufund-api/data/cupboard.json2
-rw-r--r--ufund-api/data/userAuths.json2
-rw-r--r--ufund-api/data/users.json2
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java6
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java16
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java8
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java82
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java24
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java6
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java12
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java40
-rw-r--r--ufund-ui/public/delete.pngbin6396 -> 0 bytes
-rw-r--r--ufund-ui/public/edit.pngbin6649 -> 0 bytes
-rw-r--r--ufund-ui/public/jf.pngbin0 -> 1159826 bytes
-rw-r--r--ufund-ui/public/search.pngbin12743 -> 0 bytes
-rw-r--r--ufund-ui/src/app/app-routing.module.ts14
-rw-r--r--ufund-ui/src/app/app.component.css66
-rw-r--r--ufund-ui/src/app/app.component.html19
-rw-r--r--ufund-ui/src/app/app.component.ts33
-rw-r--r--ufund-ui/src/app/app.module.ts4
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.css21
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.html13
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.ts27
-rw-r--r--ufund-ui/src/app/components/dashboard/dashboard.component.css7
-rw-r--r--ufund-ui/src/app/components/dashboard/dashboard.component.html7
-rw-r--r--ufund-ui/src/app/components/dashboard/dashboard.component.ts31
-rw-r--r--ufund-ui/src/app/components/funding-basket/funding-basket.component.ts21
-rw-r--r--ufund-ui/src/app/components/home-page/home-page.component.css37
-rw-r--r--ufund-ui/src/app/components/home-page/home-page.component.html13
-rw-r--r--ufund-ui/src/app/components/login/login.component.css30
-rw-r--r--ufund-ui/src/app/components/login/login.component.html17
-rw-r--r--ufund-ui/src/app/components/login/login.component.ts14
-rw-r--r--ufund-ui/src/app/components/mini-need-list/mini-need-list.component.css56
-rw-r--r--ufund-ui/src/app/components/mini-need-list/mini-need-list.component.html17
-rw-r--r--ufund-ui/src/app/components/mini-need-list/mini-need-list.component.ts19
-rw-r--r--ufund-ui/src/app/components/need-list/need-list.component.css121
-rw-r--r--ufund-ui/src/app/components/need-list/need-list.component.html78
-rw-r--r--ufund-ui/src/app/components/need-list/need-list.component.ts4
-rw-r--r--ufund-ui/src/app/components/need-page/need-page.component.css10
-rw-r--r--ufund-ui/src/app/components/need-page/need-page.component.html47
-rw-r--r--ufund-ui/src/app/components/signup/signup.component.css28
-rw-r--r--ufund-ui/src/app/components/signup/signup.component.html47
-rw-r--r--ufund-ui/src/app/components/signup/signup.component.ts14
-rw-r--r--ufund-ui/src/app/components/toast/toast.component.css57
-rw-r--r--ufund-ui/src/app/components/toast/toast.component.html7
-rw-r--r--ufund-ui/src/app/components/toast/toast.component.ts37
-rw-r--r--ufund-ui/src/app/models/Need.ts2
-rw-r--r--ufund-ui/src/app/services/auth.service.ts14
-rw-r--r--ufund-ui/src/app/services/toasts.service.ts27
-rw-r--r--ufund-ui/src/index.html16
-rw-r--r--ufund-ui/src/styles.css62
52 files changed, 957 insertions, 289 deletions
diff --git a/start.bat b/start.bat
new file mode 100644
index 0000000..a19b267
--- /dev/null
+++ b/start.bat
@@ -0,0 +1,9 @@
+@echo off
+
+cd ufund-api
+
+start cmd /k "mvn compile exec:java"
+
+cd ../ufund-ui
+
+start cmd /k "ng serve -o" \ No newline at end of file
diff --git a/ufund-api/data/cupboard.json b/ufund-api/data/cupboard.json
index 3d49031..0e3917f 100644
--- a/ufund-api/data/cupboard.json
+++ b/ufund-api/data/cupboard.json
@@ -1 +1 @@
-[{"name":"Pollution Filters","location":"New York Harbor","id":5,"maxGoal":1000.0,"type":"PHYSICAL","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Diving Equipment","location":"Gulf of Mexico","id":6,"maxGoal":50.0,"type":"PHYSICAL","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Life Straw","location":"RIT","id":7,"maxGoal":1.0,"type":"PHYSICAL","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Dog Fish research","location":"RIT","id":8,"maxGoal":1000000.0,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Jellyfish Glue","location":"Pacific","id":9,"maxGoal":100000.0,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Fish Food","location":"","id":10,"maxGoal":1000.0,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Harpoons","location":"Atlantic City","id":11,"maxGoal":900.0,"type":"PHYSICAL","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Sea Urchin Hats","location":"Seaworld","id":12,"maxGoal":90.0,"type":"PHYSICAL","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Awareness Exhibit","location":"Seneca Park Zoo","id":13,"maxGoal":1.0E7,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"New Whale","location":"Seneca Park Zoo","id":14,"maxGoal":1.0,"type":"PHYSICAL","urgent":false,"filterAttributes":null,"current":0.0},{"name":"New Gosnell Algae Filter","location":"Gosnell College","id":15,"maxGoal":40.0,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Awareness Lunches","location":"Colleges and Highschools","id":16,"maxGoal":5000.0,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Fish Column for RIT Tours","location":"Wallace Library","id":17,"maxGoal":2.0E7,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Submarine Matinience","location":"New York Harbor","id":18,"maxGoal":1000000.0,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Volunteer Lunches ","location":"Lake Ontario","id":19,"maxGoal":150.0,"type":"PHYSICAL","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Volunteer Misc. Equipment","location":"Lake Ontario","id":20,"maxGoal":2500.0,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Invasive eel removal","location":"Pacific Seafloor","id":21,"maxGoal":1.0E8,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Fishing Liscense Enforcement","location":"Rochester Bridges","id":22,"maxGoal":10000.0,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Waste Runoff Management","location":"RIT Watershed","id":23,"maxGoal":98000.0,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Lobbying for anti-dynamite fishing legislation","location":"Washington DC","id":24,"maxGoal":50000.0,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Lobbying for better fishing practice legislation","location":"Washington DC","id":25,"maxGoal":65000.0,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0},{"name":"Bioluminescence Tunnel","location":"Golisano College of Computing","id":26,"maxGoal":2.8E7,"type":"MONETARY","urgent":true,"filterAttributes":null,"current":0.0},{"name":"Pollution awareness campain","location":"Middle and Highschools","id":27,"maxGoal":35000.0,"type":"MONETARY","urgent":false,"filterAttributes":null,"current":0.0}] \ No newline at end of file
+[{"name":"Pollution Filters","location":"New York Harbor","id":5,"maxGoal":1000.0,"type":"PHYSICAL","urgent":true,"filterAttributes":[],"current":0.0,"description":"One thousand heavy duty pollution filters need to be installed as soon as possible throughout the new york harbor."},{"name":"Diving Equipment","location":"Gulf of Mexico","id":6,"maxGoal":120000.0,"type":"MONETARY","urgent":false,"filterAttributes":[],"current":0.0,"description":"Our research team in mexico needs new deep sea rated equipment to continue their research on the ecosystem! Until the equipment funding is fully reached and gear installed, no more progress can be made."},{"name":"Dog Fish research","location":"RIT","id":8,"maxGoal":1000000.0,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"Dog Fish are a very interesting species that many research facilities are not researching. The funding will go towards starting research papers on the species."},{"name":"Fish Food Promotion","location":"","id":10,"maxGoal":1000.0,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"The money will be spent on a small advertising campaign at a local pet store, where free fish food will be given out to people willing to listen to our cause."},{"name":"Harpoons","location":"Atlantic City","id":11,"maxGoal":25.0,"type":"PHYSICAL","urgent":false,"filterAttributes":[],"current":0.0,"description":"Harpoons are needed for an upcoming whaling museum exhibit. We aren't picky, and need any harpoons that would be interesting for display. We are accepting any harpoons at least 30 years old, but the older the better."},{"name":"Sea Urchin Hats","location":"Seaworld","id":12,"maxGoal":90.0,"type":"PHYSICAL","urgent":true,"filterAttributes":[],"current":0.0,"description":"Seaworld's sea urchins will be wearing your hats as a part of a promo! Hats donated will be used as a part of an awareness exhibit at Seaworld."},{"name":"Awareness Exhibit","location":"Seneca Park Zoo","id":13,"maxGoal":1.0E7,"type":"MONETARY","urgent":false,"filterAttributes":[],"current":0.0,"description":"Getting the Jelly Solutions message out is our top priority. We would like to open a large exhibit featuring all the endangered species due to climate change, overfishing, and pollution. Sadly, this wouldn't be cheap as we want to really get the message across to visitors through different animals, scenes, info boards, and videos."},{"name":"New Whale","location":"Seneca Park Zoo","id":14,"maxGoal":1.0,"type":"PHYSICAL","urgent":false,"filterAttributes":[],"current":0.0,"description":"Seneca park zoo needs a new whale for the upcoming promotional exhibit! The zoo will provide a commemorative plaque for the donor."},{"name":"New Gosnell Algae Filter","location":"Gosnell College","id":15,"maxGoal":40.0,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"The Gosnell College fish tank gets way to dirty way too quickly. $40 surely could replace the filter with a more effective one."},{"name":"Awareness Lunches","location":"Colleges and Highschools","id":16,"maxGoal":5000.0,"type":"MONETARY","urgent":false,"filterAttributes":[],"current":0.0,"description":"College and Highschool students would be great recruits for our volunteer events. The lunches would promote our cause and demonstrate ways that they could easily contribute to the movement."},{"name":"Fish Column for RIT Tours","location":"Wallace Library","id":17,"maxGoal":2.0E7,"type":"MONETARY","urgent":false,"filterAttributes":[],"current":0.0,"description":"RIT tours always run through Wallace Library into the SHED. What better way to encourage students to attend the college than a massive aquarium column? This would not only encourage students to join RIT, and could also raise awareness for our cause."},{"name":"Submarine Matinience","location":"New York Harbor","id":18,"maxGoal":1000000.0,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"Submarines are necessary tools that many other needs cannot function without. These urgent repairs need to happen as soon as possible."},{"name":"Volunteering for Volunteer Lunches ","location":"Lake Ontario","id":19,"maxGoal":5.0,"type":"PHYSICAL","urgent":false,"filterAttributes":[],"current":0.0,"description":"We need staff to help organize our awareness lunches! The lunches will recruit interested people into volunteering for upcoming events and cleanups."},{"name":"Volunteer Misc. Equipment","location":"Lake Ontario","id":20,"maxGoal":2500.0,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"$2500 is needed to cover the unforeseen costs of the upcoming beach cleanup. The money will be spent on nets and other tools for volunteers."},{"name":"Invasive eel removal","location":"Pacific Seafloor","id":21,"maxGoal":1.0E8,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"The population of invasive eels are destroying ecosystems. We need to remove these eels and restore balance to these ecosystems as soon as possible."},{"name":"Fishing Liscense Enforcement","location":"Rochester Bridges","id":22,"maxGoal":10000.0,"type":"MONETARY","urgent":false,"filterAttributes":[],"current":0.0,"description":"Rochester citizens won't stop fishing off bridges no matter how many times we ask. The funding will go to increased enforcement of fishing licenses in delegated stocked areas."},{"name":"Waste Runoff Management","location":"RIT Watershed","id":23,"maxGoal":98000.0,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"Waste runoff into the protected watershed near RIT is a consistent issue. We need funding to research how to best solve this problem."},{"name":"Lobbying for anti-dynamite fishing legislation","location":"Washington DC","id":24,"maxGoal":50000.0,"type":"MONETARY","urgent":false,"filterAttributes":[],"current":0.0,"description":"Dynamite fishing destroys ecosystems. Legislation needs to be passed as soon as possible! However, lobbyists aren't cheap. Any support to the fund would be greatly appreciated."},{"name":"Bioluminescence Tunnel","location":"Golisano College of Computing","id":26,"maxGoal":2.8E7,"type":"MONETARY","urgent":true,"filterAttributes":[],"current":0.0,"description":"Golisano needs a biolumenescence tunnel! The addition would be costly, but would make the building much more interesting to be in. People sometimes complain about the way the building feels, and this would be a great way to fix that."}] \ No newline at end of file
diff --git a/ufund-api/data/userAuths.json b/ufund-api/data/userAuths.json
index b703ae2..f86b1a4 100644
--- a/ufund-api/data/userAuths.json
+++ b/ufund-api/data/userAuths.json
@@ -1 +1 @@
-[{"key":"3fdd4e7e-bc59-4e3a-ba5c-177d0833022a","username":"sowgro","expiration":"2025-04-14T18:35:26.42935739"},{"key":"5d0182e2-247e-4b4e-b165-cd95710c2402","username":"phil","expiration":"2025-04-17T08:17:09.1886771"},{"key":"13d12a6d-6825-4c1d-8b22-ba960de140b8","username":"phil","expiration":"2025-04-14T17:20:58.531711142"},{"key":"960ef9a5-021d-49a1-a752-ad9dfd8a40f3","username":"phil","expiration":"2025-04-17T10:53:51.2661748"},{"key":"20529784-361d-4111-8b2e-13a23b24d6cc","username":"phil","expiration":"2025-04-17T09:07:11.4534752"},{"key":"342977bc-2095-4325-96d8-ea4cdaa241c6","username":"phil","expiration":"2025-04-17T08:47:07.5445119"},{"key":"e2c17a24-ad11-4e63-8b01-74baf3ae6b4a","username":"phil","expiration":"2025-04-17T10:14:03.2239052"},{"key":"f9f6bc24-7a69-4bfe-92c3-c1166d20f0db","username":"phil","expiration":"2025-04-17T10:50:51.9716943"},{"key":"1dc114a0-f5d7-410e-8664-2ca9af3393ac","username":"phil","expiration":"2025-04-17T09:06:49.5204299"},{"key":"ff1e80a8-344f-4578-9ead-a6d46c8ed1c2","username":"phil","expiration":"2025-04-17T10:51:00.0607854"},{"key":"eeea7b02-7265-4a26-96de-a8ad1860c533","username":"phil","expiration":"2025-03-31T23:04:47.455490668"},{"key":"e121c7c6-e534-4fde-8a78-4f175e9db9c8","username":"phil","expiration":"2025-04-14T17:23:23.218442063"},{"key":"4df8bb43-f597-49ca-863a-6e0da5280d79","username":"phil","expiration":"2025-04-14T01:13:53.799331844"},{"key":"05e8790e-67fa-45de-adfe-82c6f5fdd15b","username":"phil","expiration":"2025-04-17T08:18:05.2696558"},{"key":"4eafe9d9-1b05-4fbd-90f1-c7f856d338dd","username":"phil","expiration":"2025-04-17T09:46:48.0123639"},{"key":"1a9b7e5a-d19c-43ef-bb02-838b6fc695e0","username":"phil","expiration":"2025-04-17T09:37:48.4955941"},{"key":"718be1e2-cfc7-44a6-b3c6-965684d1d0a9","username":"adf","expiration":"2025-04-14T18:35:58.888847176"},{"key":"85319427-4603-4a16-af33-2e9525dda8c0","username":"phil","expiration":"2025-04-14T00:39:34.952183453"},{"key":"f14f187c-355f-444a-88bf-42202f82f947","username":"phil","expiration":"2025-04-17T09:07:05.5541299"},{"key":"004f9f22-2b7e-4448-9c37-7437de47f1e0","username":"phil","expiration":"2025-04-17T08:27:28.3862592"},{"key":"24e8cf17-ad76-45b1-bfb6-79a790035231","username":"admin","expiration":"2025-04-17T08:17:27.7488131"},{"key":"f1d6a110-4232-4ef3-b6ec-9a2962664158","username":"phil","expiration":"2025-04-14T17:23:40.834526839"},{"key":"e48872fa-b89f-494a-b681-11a809d32ff4","username":"phil","expiration":"2025-04-14T17:20:23.265745224"},{"key":"31fcbc15-9902-41d2-8d6f-5b0e40ebddd2","username":"phil","expiration":"2025-04-14T16:45:41.082560826"},{"key":"98c11c42-4e7c-4601-b591-a4af1a5163f9","username":"phil","expiration":"2025-04-17T08:54:04.5078852"},{"key":"27583604-609f-4dac-bb88-01c6035c4142","username":"phil","expiration":"2025-04-17T11:15:56.8479454"},{"key":"967de418-4f86-44ac-b364-eb3a1653aa7d","username":"phil","expiration":"2025-04-17T10:54:19.237888"},{"key":"f20b64c5-a7ed-48c0-a813-6d9802cf9109","username":"phil","expiration":"2025-04-17T08:41:02.6531587"},{"key":"10ea39c2-3869-47da-8630-87b21a88681d","username":"phil","expiration":"2025-04-17T08:45:33.1781528"},{"key":"92d0d6cb-ceb0-4f84-bab3-d959dfb5df9d","username":"phil","expiration":"2025-04-17T08:30:04.2567034"},{"key":"7a7d2e8b-4242-4c18-b7dd-d0565ab5c725","username":"phil","expiration":"2025-04-17T10:10:44.3380846"},{"key":"e14f8ee5-5780-4b9b-bf34-7a41c2bbfcb4","username":"phil","expiration":"2025-04-05T13:46:10.90733016"},{"key":"e1905fc6-ca86-43d7-b1e7-60d458c75a04","username":"phil","expiration":"2025-04-17T09:12:05.990995"},{"key":"a1417644-2b43-4a18-bf5a-26bf3b7ac1fc","username":"phil","expiration":"2025-04-17T10:23:26.122743"},{"key":"7e312d55-bf3e-4dc3-b44a-74d8be591287","username":"phil","expiration":"2025-04-17T10:56:38.9103348"},{"key":"af38add5-b100-4b96-9ffb-5afaccd59979","username":"adf","expiration":"2025-04-14T18:18:47.670506361"},{"key":"4ae3922b-7d5d-45c2-83eb-f8c77e3ce218","username":"phil","expiration":"2025-04-17T08:18:53.5158112"},{"key":"0eb494c8-2fa4-4ef4-915d-4b9fcb3c75ef","username":"phil","expiration":"2025-04-17T08:24:20.412242"},{"key":"0d81e2b4-d9f2-4bc0-b93f-084c086e3707","username":"phil","expiration":"2025-04-17T08:52:41.0723771"},{"key":"04900729-cdcf-4758-9c6e-4f70f03ddb86","username":"phil","expiration":"2025-04-17T11:15:05.0632779"},{"key":"0c8da4b1-bca8-42df-a5b6-65023eadab05","username":"phil","expiration":"2025-04-17T08:15:37.7698648"},{"key":"a3703b55-c7fd-4c5a-9b6a-160c1906aa1a","username":"phil","expiration":"2025-04-17T11:35:39.9101516"},{"key":"ba426671-db67-4d2f-a701-3aa0f284f497","username":"phil","expiration":"2025-04-17T08:54:43.230802"},{"key":"639ea3fa-854a-4052-b1cf-80ea1d3d5917","username":"phil","expiration":"2025-04-17T09:38:47.9716959"},{"key":"a1825159-2e62-48a3-beba-74a3daaca5b5","username":"phil","expiration":"2025-04-17T08:12:28.2166599"},{"key":"799ed420-e843-4777-8c1a-c6d061cca773","username":"phil","expiration":"2025-04-17T08:39:38.8493536"},{"key":"cdd4df80-8139-4479-86ec-953190796d7b","username":"phil","expiration":"2025-04-17T10:02:07.6745458"},{"key":"3d3fb646-9954-496b-98bf-73136c7792ea","username":"phil","expiration":"2025-04-17T10:04:11.7737565"},{"key":"da61796e-402a-4a80-88ae-7607a37989a4","username":"phil","expiration":"2025-04-14T17:07:10.618039573"},{"key":"3beac724-e9f9-4969-9634-60826ad9db43","username":"phil","expiration":"2025-04-17T11:20:36.8424562"},{"key":"0d6e6910-b5dc-45ae-ba8e-c28604939f83","username":"phil","expiration":"2025-04-17T11:19:21.9682553"},{"key":"b7b403a0-d81f-4f7d-bd28-ccf3e2ac706b","username":"phil","expiration":"2025-04-17T10:28:53.9964744"},{"key":"125a4847-3a1c-4834-961f-7f96e997f92e","username":"sowgro","expiration":"2025-04-14T18:35:38.922687686"},{"key":"ce4accc3-0fa8-40fc-a480-1290d12caaed","username":"phil","expiration":"2025-04-17T09:12:58.9504986"},{"key":"adc5ce2f-5a40-4ee5-b9a6-6154860e6861","username":"phil","expiration":"2025-04-17T08:28:48.4584821"},{"key":"2aeaab28-99c9-4b45-bdef-82096c70945e","username":"phil","expiration":"2025-04-14T17:19:48.552121268"},{"key":"7805de89-9b38-46dc-8f59-09c06ef9d2dd","username":"phil","expiration":"2025-04-17T08:52:44.6283659"},{"key":"ad6d92d4-c496-407c-823a-edaa386e67ed","username":"phil","expiration":"2025-04-14T17:07:36.032623002"},{"key":"fbdf7ac2-cf01-4dad-baec-ed9310a4eba7","username":"phil","expiration":"2025-04-17T08:38:12.8162926"},{"key":"7907ccb2-bf01-4962-a280-ebb6aa9c5b20","username":"phil","expiration":"2025-04-17T09:45:01.6777324"},{"key":"a69796dd-734c-4545-ac91-e5fe0387d0ad","username":"phil","expiration":"2025-04-17T08:29:32.671782"},{"key":"9f3e380d-fead-4d40-a1c0-278e857dd674","username":"phil","expiration":"2025-04-17T08:52:29.4148814"},{"key":"efc531fb-ab24-4d5a-a2f5-7f4ede74819f","username":"phil","expiration":"2025-04-13T19:41:51.017327545"},{"key":"88b539a9-3986-41b4-a6ed-a79672042ccf","username":"phil","expiration":"2025-04-17T08:23:45.5712888"},{"key":"68bc53af-e21a-4364-adf5-8f163f642235","username":"phil","expiration":"2025-04-17T08:24:43.3201656"},{"key":"a07ae51f-f80b-4001-95f1-48c11d4917a4","username":"phil","expiration":"2025-04-05T15:04:30.900359001"},{"key":"cc49c007-fd36-4828-b8fa-f5b85ad0676d","username":"phil","expiration":"2025-04-14T16:46:12.80566798"},{"key":"fb2d7dd5-783e-47d8-9a43-8b7693c5f070","username":"phil","expiration":"2025-04-17T11:13:05.9489267"},{"key":"49a0ad40-3223-4f62-94e8-0f9e96241a85","username":"phil","expiration":"2025-04-17T09:13:39.9633546"},{"key":"db53acf2-61d1-45ea-9d01-5c710b80bdaf","username":"phil","expiration":"2025-04-17T08:53:47.487545"},{"key":"d7cef571-0f76-49fe-941f-ecbeae69557a","username":"phil","expiration":"2025-04-05T15:14:00.363201102"},{"key":"3fc557b6-0306-4779-9b74-b7292a5cf1cc","username":"phil","expiration":"2025-04-14T16:06:08.564069822"},{"key":"77392d17-6e0c-45ec-857d-6595a55ddd97","username":"phil","expiration":"2025-04-14T16:06:48.335542315"},{"key":"58e4e2a2-3a36-4fd6-8bb1-ad0831664d01","username":"phil","expiration":"2025-04-12T23:17:42.638952959"},{"key":"6083ae1d-a761-4ed3-8c48-a429afa2c521","username":"phil","expiration":"2025-04-17T08:32:25.3500545"},{"key":"1c438301-e8f5-4c12-a40b-e20b8a282814","username":"keshey","expiration":"2025-04-17T10:26:04.7690496"},{"key":"fe2146e2-7982-4226-b215-96879939f485","username":"phil","expiration":"2025-04-17T08:34:59.3412483"},{"key":"6d2ea170-50aa-4c48-9247-9310a29ae753","username":"phil","expiration":"2025-04-17T11:29:10.0637357"},{"key":"f5f53053-ef5e-4850-93a0-3dc20646f78b","username":"sowgro","expiration":"2025-04-14T18:11:29.438554549"},{"key":"03424ad1-376c-47aa-8553-7f2ea8099d45","username":"phil","expiration":"2025-04-17T08:05:35.7264696"},{"key":"568e4738-70b5-4be7-bfa6-1367cd22ce3f","username":"admin","expiration":"2025-04-17T08:16:59.0542222"},{"key":"7a634e0a-628b-4b31-8950-dc33d4ee5d95","username":"phil","expiration":"2025-04-17T08:15:47.1663258"},{"key":"9c6a36b8-7f71-4b09-b26b-682f1f0be4cb","username":"phil","expiration":"2025-04-17T09:12:15.5425885"},{"key":"f6951471-2578-4a6a-b3e5-b7e97ed9207a","username":"phil","expiration":"2025-04-17T10:23:45.9450825"},{"key":"cb658550-aafc-4a45-89be-f7899e44d7ba","username":"phil","expiration":"2025-04-17T10:50:40.0249774"}] \ No newline at end of file
+[{"key":"3fdd4e7e-bc59-4e3a-ba5c-177d0833022a","username":"sowgro","expiration":"2025-04-14T18:35:26.42935739"},{"key":"5d0182e2-247e-4b4e-b165-cd95710c2402","username":"phil","expiration":"2025-04-17T08:17:09.1886771"},{"key":"13d12a6d-6825-4c1d-8b22-ba960de140b8","username":"phil","expiration":"2025-04-14T17:20:58.531711142"},{"key":"960ef9a5-021d-49a1-a752-ad9dfd8a40f3","username":"phil","expiration":"2025-04-17T10:53:51.2661748"},{"key":"20529784-361d-4111-8b2e-13a23b24d6cc","username":"phil","expiration":"2025-04-17T09:07:11.4534752"},{"key":"342977bc-2095-4325-96d8-ea4cdaa241c6","username":"phil","expiration":"2025-04-17T08:47:07.5445119"},{"key":"e2c17a24-ad11-4e63-8b01-74baf3ae6b4a","username":"phil","expiration":"2025-04-17T10:14:03.2239052"},{"key":"f9f6bc24-7a69-4bfe-92c3-c1166d20f0db","username":"phil","expiration":"2025-04-17T10:50:51.9716943"},{"key":"1dc114a0-f5d7-410e-8664-2ca9af3393ac","username":"phil","expiration":"2025-04-17T09:06:49.5204299"},{"key":"ff1e80a8-344f-4578-9ead-a6d46c8ed1c2","username":"phil","expiration":"2025-04-17T10:51:00.0607854"},{"key":"eeea7b02-7265-4a26-96de-a8ad1860c533","username":"phil","expiration":"2025-03-31T23:04:47.455490668"},{"key":"e121c7c6-e534-4fde-8a78-4f175e9db9c8","username":"phil","expiration":"2025-04-14T17:23:23.218442063"},{"key":"4df8bb43-f597-49ca-863a-6e0da5280d79","username":"phil","expiration":"2025-04-14T01:13:53.799331844"},{"key":"05e8790e-67fa-45de-adfe-82c6f5fdd15b","username":"phil","expiration":"2025-04-17T08:18:05.2696558"},{"key":"4eafe9d9-1b05-4fbd-90f1-c7f856d338dd","username":"phil","expiration":"2025-04-17T09:46:48.0123639"},{"key":"1a9b7e5a-d19c-43ef-bb02-838b6fc695e0","username":"phil","expiration":"2025-04-17T09:37:48.4955941"},{"key":"718be1e2-cfc7-44a6-b3c6-965684d1d0a9","username":"adf","expiration":"2025-04-14T18:35:58.888847176"},{"key":"85319427-4603-4a16-af33-2e9525dda8c0","username":"phil","expiration":"2025-04-14T00:39:34.952183453"},{"key":"f14f187c-355f-444a-88bf-42202f82f947","username":"phil","expiration":"2025-04-17T09:07:05.5541299"},{"key":"004f9f22-2b7e-4448-9c37-7437de47f1e0","username":"phil","expiration":"2025-04-17T08:27:28.3862592"},{"key":"24e8cf17-ad76-45b1-bfb6-79a790035231","username":"admin","expiration":"2025-04-17T08:17:27.7488131"},{"key":"f1d6a110-4232-4ef3-b6ec-9a2962664158","username":"phil","expiration":"2025-04-14T17:23:40.834526839"},{"key":"e48872fa-b89f-494a-b681-11a809d32ff4","username":"phil","expiration":"2025-04-14T17:20:23.265745224"},{"key":"31fcbc15-9902-41d2-8d6f-5b0e40ebddd2","username":"phil","expiration":"2025-04-14T16:45:41.082560826"},{"key":"98c11c42-4e7c-4601-b591-a4af1a5163f9","username":"phil","expiration":"2025-04-17T08:54:04.5078852"},{"key":"27583604-609f-4dac-bb88-01c6035c4142","username":"phil","expiration":"2025-04-17T11:15:56.8479454"},{"key":"967de418-4f86-44ac-b364-eb3a1653aa7d","username":"phil","expiration":"2025-04-17T10:54:19.237888"},{"key":"f20b64c5-a7ed-48c0-a813-6d9802cf9109","username":"phil","expiration":"2025-04-17T08:41:02.6531587"},{"key":"10ea39c2-3869-47da-8630-87b21a88681d","username":"phil","expiration":"2025-04-17T08:45:33.1781528"},{"key":"92d0d6cb-ceb0-4f84-bab3-d959dfb5df9d","username":"phil","expiration":"2025-04-17T08:30:04.2567034"},{"key":"7a7d2e8b-4242-4c18-b7dd-d0565ab5c725","username":"phil","expiration":"2025-04-17T10:10:44.3380846"},{"key":"e14f8ee5-5780-4b9b-bf34-7a41c2bbfcb4","username":"phil","expiration":"2025-04-05T13:46:10.90733016"},{"key":"e1905fc6-ca86-43d7-b1e7-60d458c75a04","username":"phil","expiration":"2025-04-17T09:12:05.990995"},{"key":"a1417644-2b43-4a18-bf5a-26bf3b7ac1fc","username":"phil","expiration":"2025-04-17T10:23:26.122743"},{"key":"7e312d55-bf3e-4dc3-b44a-74d8be591287","username":"phil","expiration":"2025-04-17T10:56:38.9103348"},{"key":"af38add5-b100-4b96-9ffb-5afaccd59979","username":"adf","expiration":"2025-04-14T18:18:47.670506361"},{"key":"4ae3922b-7d5d-45c2-83eb-f8c77e3ce218","username":"phil","expiration":"2025-04-17T08:18:53.5158112"},{"key":"0eb494c8-2fa4-4ef4-915d-4b9fcb3c75ef","username":"phil","expiration":"2025-04-17T08:24:20.412242"},{"key":"0d81e2b4-d9f2-4bc0-b93f-084c086e3707","username":"phil","expiration":"2025-04-17T08:52:41.0723771"},{"key":"04900729-cdcf-4758-9c6e-4f70f03ddb86","username":"phil","expiration":"2025-04-17T11:15:05.0632779"},{"key":"0c8da4b1-bca8-42df-a5b6-65023eadab05","username":"phil","expiration":"2025-04-17T08:15:37.7698648"},{"key":"a3703b55-c7fd-4c5a-9b6a-160c1906aa1a","username":"phil","expiration":"2025-04-17T11:35:39.9101516"},{"key":"ba426671-db67-4d2f-a701-3aa0f284f497","username":"phil","expiration":"2025-04-17T08:54:43.230802"},{"key":"639ea3fa-854a-4052-b1cf-80ea1d3d5917","username":"phil","expiration":"2025-04-17T09:38:47.9716959"},{"key":"a1825159-2e62-48a3-beba-74a3daaca5b5","username":"phil","expiration":"2025-04-17T08:12:28.2166599"},{"key":"799ed420-e843-4777-8c1a-c6d061cca773","username":"phil","expiration":"2025-04-17T08:39:38.8493536"},{"key":"cdd4df80-8139-4479-86ec-953190796d7b","username":"phil","expiration":"2025-04-17T10:02:07.6745458"},{"key":"3d3fb646-9954-496b-98bf-73136c7792ea","username":"phil","expiration":"2025-04-17T10:04:11.7737565"},{"key":"da61796e-402a-4a80-88ae-7607a37989a4","username":"phil","expiration":"2025-04-14T17:07:10.618039573"},{"key":"3beac724-e9f9-4969-9634-60826ad9db43","username":"phil","expiration":"2025-04-17T11:20:36.8424562"},{"key":"0d6e6910-b5dc-45ae-ba8e-c28604939f83","username":"phil","expiration":"2025-04-17T11:19:21.9682553"},{"key":"b7b403a0-d81f-4f7d-bd28-ccf3e2ac706b","username":"phil","expiration":"2025-04-17T10:28:53.9964744"},{"key":"125a4847-3a1c-4834-961f-7f96e997f92e","username":"sowgro","expiration":"2025-04-14T18:35:38.922687686"},{"key":"ce4accc3-0fa8-40fc-a480-1290d12caaed","username":"phil","expiration":"2025-04-17T09:12:58.9504986"},{"key":"adc5ce2f-5a40-4ee5-b9a6-6154860e6861","username":"phil","expiration":"2025-04-17T08:28:48.4584821"},{"key":"50019b5d-25ad-40fe-bd21-19d4dbe57a92","username":"phil","expiration":"2025-04-29T20:23:12.415416825"},{"key":"2aeaab28-99c9-4b45-bdef-82096c70945e","username":"phil","expiration":"2025-04-14T17:19:48.552121268"},{"key":"7805de89-9b38-46dc-8f59-09c06ef9d2dd","username":"phil","expiration":"2025-04-17T08:52:44.6283659"},{"key":"ad6d92d4-c496-407c-823a-edaa386e67ed","username":"phil","expiration":"2025-04-14T17:07:36.032623002"},{"key":"fbdf7ac2-cf01-4dad-baec-ed9310a4eba7","username":"phil","expiration":"2025-04-17T08:38:12.8162926"},{"key":"7907ccb2-bf01-4962-a280-ebb6aa9c5b20","username":"phil","expiration":"2025-04-17T09:45:01.6777324"},{"key":"904f6de1-10ab-465d-abd8-be0612311251","username":"phil","expiration":"2025-04-29T20:24:45.666998397"},{"key":"a69796dd-734c-4545-ac91-e5fe0387d0ad","username":"phil","expiration":"2025-04-17T08:29:32.671782"},{"key":"9f3e380d-fead-4d40-a1c0-278e857dd674","username":"phil","expiration":"2025-04-17T08:52:29.4148814"},{"key":"efc531fb-ab24-4d5a-a2f5-7f4ede74819f","username":"phil","expiration":"2025-04-13T19:41:51.017327545"},{"key":"88b539a9-3986-41b4-a6ed-a79672042ccf","username":"phil","expiration":"2025-04-17T08:23:45.5712888"},{"key":"68bc53af-e21a-4364-adf5-8f163f642235","username":"phil","expiration":"2025-04-17T08:24:43.3201656"},{"key":"a07ae51f-f80b-4001-95f1-48c11d4917a4","username":"phil","expiration":"2025-04-05T15:04:30.900359001"},{"key":"cc49c007-fd36-4828-b8fa-f5b85ad0676d","username":"phil","expiration":"2025-04-14T16:46:12.80566798"},{"key":"fb2d7dd5-783e-47d8-9a43-8b7693c5f070","username":"phil","expiration":"2025-04-17T11:13:05.9489267"},{"key":"49a0ad40-3223-4f62-94e8-0f9e96241a85","username":"phil","expiration":"2025-04-17T09:13:39.9633546"},{"key":"db53acf2-61d1-45ea-9d01-5c710b80bdaf","username":"phil","expiration":"2025-04-17T08:53:47.487545"},{"key":"d7cef571-0f76-49fe-941f-ecbeae69557a","username":"phil","expiration":"2025-04-05T15:14:00.363201102"},{"key":"25d6a49b-c185-460c-adbe-a874419d20aa","username":"phil","expiration":"2025-04-29T20:22:19.629805123"},{"key":"3fc557b6-0306-4779-9b74-b7292a5cf1cc","username":"phil","expiration":"2025-04-14T16:06:08.564069822"},{"key":"77392d17-6e0c-45ec-857d-6595a55ddd97","username":"phil","expiration":"2025-04-14T16:06:48.335542315"},{"key":"58e4e2a2-3a36-4fd6-8bb1-ad0831664d01","username":"phil","expiration":"2025-04-12T23:17:42.638952959"},{"key":"6083ae1d-a761-4ed3-8c48-a429afa2c521","username":"phil","expiration":"2025-04-17T08:32:25.3500545"},{"key":"1c438301-e8f5-4c12-a40b-e20b8a282814","username":"keshey","expiration":"2025-04-17T10:26:04.7690496"},{"key":"fe2146e2-7982-4226-b215-96879939f485","username":"phil","expiration":"2025-04-17T08:34:59.3412483"},{"key":"6d2ea170-50aa-4c48-9247-9310a29ae753","username":"phil","expiration":"2025-04-17T11:29:10.0637357"},{"key":"f5f53053-ef5e-4850-93a0-3dc20646f78b","username":"sowgro","expiration":"2025-04-14T18:11:29.438554549"},{"key":"03424ad1-376c-47aa-8553-7f2ea8099d45","username":"phil","expiration":"2025-04-17T08:05:35.7264696"},{"key":"568e4738-70b5-4be7-bfa6-1367cd22ce3f","username":"admin","expiration":"2025-04-17T08:16:59.0542222"},{"key":"7a634e0a-628b-4b31-8950-dc33d4ee5d95","username":"phil","expiration":"2025-04-17T08:15:47.1663258"},{"key":"9c6a36b8-7f71-4b09-b26b-682f1f0be4cb","username":"phil","expiration":"2025-04-17T09:12:15.5425885"},{"key":"f6951471-2578-4a6a-b3e5-b7e97ed9207a","username":"phil","expiration":"2025-04-17T10:23:45.9450825"},{"key":"cb658550-aafc-4a45-89be-f7899e44d7ba","username":"phil","expiration":"2025-04-17T10:50:40.0249774"}] \ No newline at end of file
diff --git a/ufund-api/data/users.json b/ufund-api/data/users.json
index 5b2457f..9bddb7d 100644
--- a/ufund-api/data/users.json
+++ b/ufund-api/data/users.json
@@ -1 +1 @@
-[{"username":"keshey","passwordHash":-1134843357,"basket":[],"type":"HELPER"},{"username":"admin","passwordHash":92668751,"basket":[],"type":"MANAGER"},{"username":"phil","passwordHash":-1054080181,"basket":[22,26],"type":"HELPER"}] \ No newline at end of file
+[{"username":"keshey","passwordHash":-1134843357,"basket":[],"type":"HELPER"},{"username":"admin","passwordHash":92668751,"basket":[],"type":"MANAGER"},{"username":"phil","passwordHash":-1054080181,"basket":[],"type":"HELPER"}] \ No newline at end of file
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java
index cce016c..12fb0a9 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java
@@ -5,7 +5,6 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
-import com.ufund.api.ufundapi.service.AuthService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -22,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.ufund.api.ufundapi.DuplicateKeyException;
import com.ufund.api.ufundapi.model.Need;
import com.ufund.api.ufundapi.model.Need.GoalType;
+import com.ufund.api.ufundapi.service.AuthService;
import com.ufund.api.ufundapi.service.CupboardService;
@RestController
@@ -55,14 +55,16 @@ public class CupboardController {
LOG.log(Level.INFO, "POST /cupboard body={0}", params);
String name = (String) params.get("name");
+ String image = (String) params.get("image");
String location = (String) params.get("location");
double maxGoal = ((Number) params.get("maxGoal")).doubleValue();
boolean urgent = (Boolean) params.get("urgent");
+ String description = (String) params.get("description");
Need.GoalType goalType = GoalType.valueOf((String) params.get("type"));
try {
authService.keyHasAccessToCupboard(key);
- Need need = cupboardService.createNeed(name, location, maxGoal, goalType, urgent);
+ Need need = cupboardService.createNeed(name, image, location, maxGoal, goalType, urgent, description);
return new ResponseEntity<>(need, HttpStatus.OK);
} catch (DuplicateKeyException ex) {
LOG.log(Level.WARNING, ex.getLocalizedMessage());
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java
index 55a9441..9b6170b 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java
@@ -10,6 +10,7 @@ public class Need {
}
@JsonProperty("name") private String name;
+ @JsonProperty("image") private String image;
@JsonProperty("location") private String location;
@JsonProperty("id") private int id;
@JsonProperty("filterAttributes") private String[] filterAttributes;
@@ -17,6 +18,7 @@ public class Need {
@JsonProperty("maxGoal") private double maxGoal;
@JsonProperty("urgent") private boolean urgent;
@JsonProperty("current") private double current;
+ @JsonProperty("description") private String description;
/**
* Create a new need, used by the controller
@@ -27,31 +29,38 @@ public class Need {
* @param maxGoal The maximum goal for this need
* @param type The type of need (monetary, physical)
* @param urgent The urgency of the need
+ * @param description The description of the need
*/
- public Need(@JsonProperty("name") String name, @JsonProperty("location") String location, @JsonProperty("id") int id, @JsonProperty("maxGoal") double maxGoal, @JsonProperty("type") GoalType type, @JsonProperty("urgent") boolean urgent) {
+ public Need(@JsonProperty("name") String name, @JsonProperty("image") String image, @JsonProperty("location") String location, @JsonProperty("id") int id, @JsonProperty("maxGoal") double maxGoal, @JsonProperty("type") GoalType type, @JsonProperty("urgent") boolean urgent, @JsonProperty("Description") String description) {
this.id = id;
+ this.image = image;
this.location = location;
this.name = name;
this.maxGoal = maxGoal;
this.type = type;
this.urgent = urgent;
+ this.description = description;
}
/**
* Create a new need
*
* @param name The name of the need
+ * @param image The image representation of the need
* @param location The location of the need
* @param maxGoal The maximum goal for this need
* @param type The type of need (monetary, physical)
* @param urgent The urgency of the need
+ * @param description The description of the need
*/
- public Need(String name, String location, double maxGoal, GoalType type, boolean urgent) {
+ public Need(String name, String image, String location, double maxGoal, GoalType type, boolean urgent, String description) {
this.name = name;
+ this.image = image;
this.location = location;
this.type = type;
this.maxGoal = maxGoal;
this.urgent = urgent;
+ this.description = description;
}
/**
@@ -61,6 +70,7 @@ public class Need {
*/
public Need(Need other) {
this.name = other.name;
+ this.image = other.image;
this.location = other.location;
this.id = other.id;
this.filterAttributes = other.filterAttributes;
@@ -68,6 +78,7 @@ public class Need {
this.maxGoal = other.maxGoal;
this.current = other.current;
this.urgent = other.urgent;
+ this.description = other.description;
}
public String getName() {
@@ -94,6 +105,7 @@ public class Need {
return current;
}
+
public void setCurrent(double current) {
this.current = current;
}
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java
index a86fe28..993e7c1 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java
@@ -25,13 +25,17 @@ public class CupboardService {
* Creates a new Need
*
* @param name The name of the need to create
+ * @param image The image representation of the need to create
+ * @param location The location of the new need
* @param maxGoal The max goal of the new need
* @param goalType The goal type of the new need
+ * @param urgent The urgency of the new need
+ * @param description The description of the new need
* @return The need that was created
* @throws IOException Thrown if there was any issue saving the data
* @throws DuplicateKeyException If there already exists a need with the same name
*/
- public Need createNeed(String name, String location, double maxGoal, Need.GoalType goalType, boolean urgent) throws IOException, DuplicateKeyException {
+ public Need createNeed(String name, String image, String location, double maxGoal, Need.GoalType goalType, boolean urgent, String description) throws IOException, DuplicateKeyException {
if (maxGoal <= 0) {
throw new IllegalArgumentException("Max Goal must be greater than zero");
@@ -45,7 +49,7 @@ public class CupboardService {
}
}
- Need need = new Need(name, location, maxGoal, goalType, urgent);
+ Need need = new Need(name, image, location, maxGoal, goalType, urgent, description);
return cupboardDAO.addNeed(need);
}
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java
index c159db4..8572ec6 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java
@@ -43,16 +43,20 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
- when(mockCupboardService.createNeed(name, "Atlantis", maxGoal, type, false)).thenReturn(need);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
+ when(mockCupboardService.createNeed(name, image, location, maxGoal, type, urgent, description)).thenReturn(need);
Map<String, Object> needMap = Map.ofEntries(
entry("name", "Test"),
+ entry("image", ""),
entry("location", "Atlantis"),
- entry("maxGoal", 100.0),
+ entry("maxGoal", 100),
entry("type", "MONETARY"),
- entry("urgent", false)
+ entry("urgent", false),
+ entry("description", "")
);
var res = cupboardController.createNeed(needMap, key);
@@ -63,14 +67,16 @@ public class CupboardControllerTest {
@Test
public void createNeedBadMaxGoal() throws IOException, DuplicateKeyException {
- when(mockCupboardService.createNeed("Test", "Atlantis", -100, Need.GoalType.MONETARY, false)).thenThrow(new IllegalArgumentException());
+ when(mockCupboardService.createNeed("Test", "", "Atlantis", -100, Need.GoalType.MONETARY, false, "")).thenThrow(new IllegalArgumentException());
Map<String, Object> needMap = Map.ofEntries(
entry("name", "Test"),
+ entry("image", ""),
entry("location", "Atlantis"),
entry("maxGoal", -100),
entry("type", "MONETARY"),
- entry("urgent", false)
+ entry("urgent", false),
+ entry("description", "")
);
var res = cupboardController.createNeed(needMap, key);
@@ -80,14 +86,16 @@ public class CupboardControllerTest {
@Test
public void createNeedIOException() throws IOException, DuplicateKeyException {
- when(mockCupboardService.createNeed("Test", "Atlantis", 100, Need.GoalType.MONETARY, false)).thenThrow(new IOException());
+ when(mockCupboardService.createNeed("Test", "", "Atlantis", 100, Need.GoalType.MONETARY, false, "")).thenThrow(new IOException());
Map<String, Object> needMap = Map.ofEntries(
entry("name", "Test"),
+ entry("image", ""),
entry("location", "Atlantis"),
entry("maxGoal", 100),
entry("type", "MONETARY"),
- entry("urgent", false)
+ entry("urgent", false),
+ entry("description", "")
);
var res = cupboardController.createNeed(needMap, key);
@@ -97,14 +105,16 @@ public class CupboardControllerTest {
@Test
public void createNeedConflict() throws IOException, DuplicateKeyException {
- when(mockCupboardService.createNeed("Test", "Atlantis", 100, Need.GoalType.MONETARY, false)).thenThrow(new DuplicateKeyException(""));
+ when(mockCupboardService.createNeed("Test", "", "Atlantis", 100, Need.GoalType.MONETARY, false, "")).thenThrow(new DuplicateKeyException(""));
Map<String, Object> needMap = Map.ofEntries(
entry("name", "Test"),
+ entry("image", ""),
entry("location", "Atlantis"),
entry("maxGoal", 100),
entry("type", "MONETARY"),
- entry("urgent", false)
+ entry("urgent", false),
+ entry("description", "")
);
var res = cupboardController.createNeed(needMap, key);
@@ -136,7 +146,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeeds()).thenReturn(new Need[]{need});
var res = cupboardController.getNeeds();
@@ -171,7 +183,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.searchNeeds("Na")).thenReturn(new Need[]{need});
var res = cupboardController.searchNeeds("Na");
@@ -206,7 +220,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeed(need.getId())).thenReturn(need);
var res = cupboardController.getNeed(need.getId());
@@ -222,7 +238,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeed(need.getId())).thenThrow(new IOException());
var res = cupboardController.getNeed(need.getId());
@@ -237,7 +255,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeed(need.getId())).thenReturn(null);
var res = cupboardController.getNeed(need.getId());
@@ -253,7 +273,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.updateNeed(need, 1)).thenReturn(need);
var res = cupboardController.updateNeed(need, 1, key);
@@ -269,7 +291,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.updateNeed(need, 1)).thenThrow(new IOException());
var res = cupboardController.updateNeed(need, 1, key);
@@ -284,7 +308,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.updateNeed(need, 1)).thenReturn(null);
var res = cupboardController.updateNeed(need, 1, key);
@@ -299,7 +325,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.updateNeed(need, 1)).thenThrow(new IllegalArgumentException());
var res = cupboardController.updateNeed(need, 1, key);
@@ -314,7 +342,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
doThrow(new IllegalAccessException()).when(mockAuthService).keyHasAccessToCupboard(key);
var res = cupboardController.updateNeed(need, 1, key);
@@ -329,7 +359,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeed(1)).thenReturn(need);
when(mockCupboardService.deleteNeed(1)).thenReturn(true);
@@ -355,7 +387,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeed(1)).thenReturn(need);
doThrow(new IllegalAccessException()).when(mockAuthService).keyHasAccessToCupboard(key);
@@ -371,7 +405,9 @@ public class CupboardControllerTest {
int maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
when(mockCupboardService.getNeed(1)).thenReturn(need);
when(mockCupboardService.deleteNeed(1)).thenThrow(new IOException());
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java
index c7d17c7..67d2b8f 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java
@@ -18,7 +18,9 @@ public class NeedTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
assertNotNull(need);
}
@@ -29,7 +31,9 @@ public class NeedTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
assertEquals(name, need.getName());
@@ -45,7 +49,9 @@ public class NeedTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
double current = 0.00;
need.setCurrent(current);
@@ -69,7 +75,9 @@ public class NeedTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
String[] filterAttributes = {"seaweed", "divers", "pacific", "plankton"};
@@ -86,7 +94,9 @@ public class NeedTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
double newGoal = 200.00;
need.setMaxGoal(newGoal);
@@ -103,7 +113,9 @@ public class NeedTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, location, image, maxGoal, type, urgent, description);
String newName = "TESTINGFUN";
need.setName(newName);
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java
index 01b558c..ed48f54 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java
@@ -52,7 +52,7 @@ public class UserTest {
String expectedName = "Bob";
User user = User.create(expectedName, "pass");
- Need need = new Need("Test", "Atlantis", 0, 100, Need.GoalType.MONETARY, false);
+ Need need = new Need("Test", "", "Atlantis", 0, 100, Need.GoalType.MONETARY, false, "");
Need[] needs = { need };
when(cupboardService.getNeed(0)).thenReturn(need);
@@ -71,8 +71,8 @@ public class UserTest {
String expectedName = "Bob";
User user = User.create(expectedName, "pass");
- Need need = new Need("Test", "Atlantis", 0, 100, Need.GoalType.MONETARY, false);
- Need need2 = new Need("Test2", "Atlantis", 0, 100, Need.GoalType.MONETARY, false);
+ Need need = new Need("Test", "", "Atlantis", 0, 100, Need.GoalType.MONETARY, false, "");
+ Need need2 = new Need("Test2", "", "Atlantis", 0, 100, Need.GoalType.MONETARY, false, "");
when(cupboardService.getNeed(0)).thenReturn(need2);
user.addToBasket(need);
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java
index acb759a..76a8b40 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java
@@ -28,9 +28,9 @@ public class CupboardFileDAOTest {
public void setupCupboardFileDao() throws IOException {
ObjectMapper mockObjectMapper = mock(ObjectMapper.class);
testNeeds = new Need[] {
- new Need("one", "Atlantis", 0, 100, Need.GoalType.MONETARY, false),
- new Need("two", "Atlantis", 1, 100, Need.GoalType.MONETARY, false),
- new Need("three", "Atlantis", 2, 100, Need.GoalType.MONETARY, false)
+ new Need("one", "", "Atlantis", 0, 100, Need.GoalType.MONETARY, false, ""),
+ new Need("two", "", "Atlantis", 1, 100, Need.GoalType.MONETARY, false, ""),
+ new Need("three", "", "Atlantis", 2, 100, Need.GoalType.MONETARY, false, "")
};
// When the object mapper is supposed to read from the file
// the mock object mapper will return the hero array above
@@ -54,7 +54,7 @@ public class CupboardFileDAOTest {
@Test
public void createNeedTest() throws IOException {
- Need newNeed = new Need("sea urchin hats", "Atlantis", 100, GoalType.PHYSICAL, false);
+ Need newNeed = new Need("sea urchin hats", "", "Atlantis", 100, GoalType.PHYSICAL, false, "");
Need actualNeed = cupboardFileDao.addNeed(newNeed);
@@ -90,7 +90,7 @@ public class CupboardFileDAOTest {
Need unupdatedNeed = needs[needs.length - 1];
assertNotNull(unupdatedNeed);
- Need updatedNeed = new Need("sequin sea urchin hats", "Atlantis", 100, GoalType.PHYSICAL, false);
+ Need updatedNeed = new Need("sequin sea urchin hats", "", "Atlantis", 100, GoalType.PHYSICAL, false, "");
Need actualNeed = cupboardFileDao.updateNeed(updatedNeed);
assertEquals(actualNeed, updatedNeed);
@@ -103,7 +103,7 @@ public class CupboardFileDAOTest {
Need unupdatedNeed = needs[needs.length - 1];
assertNotNull(unupdatedNeed);
- Need updatedNeed = new Need("sequin sea urchin hats", "Atlantis", 5, 100, GoalType.PHYSICAL, false);
+ Need updatedNeed = new Need("sequin sea urchin hats", "", "Atlantis", 5, 100, GoalType.PHYSICAL, false, "");
Need actualNeed = cupboardFileDao.updateNeed(updatedNeed);
assertNull(actualNeed);
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java
index f3cbc23..2a3c8ee 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java
@@ -40,14 +40,16 @@ public class CupboardServiceTest {
double maxGoal = 100;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
// When the same id is passed in, our mock User DAO will return the User object
when(mockCupboardDAO.addNeed(any())).thenReturn(need);
when(mockCupboardDAO.getNeeds()).thenReturn(new Need[0]);
// Invoke
- Need response = cupboardService.createNeed(name, location, maxGoal, type, urgent);
+ Need response = cupboardService.createNeed(name, location, image, maxGoal, type, urgent, description);
// Analyze
assertNotNull(response);
@@ -62,7 +64,9 @@ public class CupboardServiceTest {
double maxGoal = -100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
// When the same id is passed in, our mock User DAO will return the User object
when(mockCupboardDAO.addNeed(any())).thenReturn(need);
@@ -73,7 +77,7 @@ public class CupboardServiceTest {
// Analyze
assertThrows(IllegalArgumentException.class, () ->
- cupboardService.createNeed(name, location, maxGoal, type, urgent));
+ cupboardService.createNeed(name, location, image, maxGoal, type, urgent, description));
}
@Test
@@ -84,7 +88,9 @@ public class CupboardServiceTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
Need[] needs = { need };
// When the same id is passed in, our mock User DAO will return the User object
@@ -96,7 +102,7 @@ public class CupboardServiceTest {
// Analyze
assertThrows(DuplicateKeyException.class, () ->
- cupboardService.createNeed(name, location, maxGoal, type, urgent));
+ cupboardService.createNeed(name, location, image, maxGoal, type, urgent, description));
}
@Test
@@ -107,7 +113,9 @@ public class CupboardServiceTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
Need[] needs = { need };
// When the same id is passed in, our mock User DAO will return the User object
@@ -129,7 +137,9 @@ public class CupboardServiceTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
Need[] needs = { need };
// When the same id is passed in, our mock User DAO will return the User object
@@ -150,7 +160,9 @@ public class CupboardServiceTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- var need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
// When the same id is passed in, our mock User DAO will return the User object
when(mockCupboardDAO.getNeed(0)).thenReturn(need);
@@ -170,8 +182,10 @@ public class CupboardServiceTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- Need need = new Need(name, location, maxGoal, type, urgent);
- Need newNeed = new Need("Octopus", location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
+ Need newNeed = new Need("Octopus", image, location, maxGoal, type, urgent, description);
// When the same id is passed in, our mock User DAO will return the User object
when(mockCupboardDAO.updateNeed(any())).thenReturn(newNeed);
@@ -191,7 +205,9 @@ public class CupboardServiceTest {
double maxGoal = 100.0;
GoalType type = Need.GoalType.MONETARY;
boolean urgent = false;
- Need need = new Need(name, location, maxGoal, type, urgent);
+ String image = "";
+ String description = "";
+ var need = new Need(name, image, location, maxGoal, type, urgent, description);
// When the same id is passed in, our mock User DAO will return the User object
when(mockCupboardDAO.deleteNeed(0)).thenReturn(true);
diff --git a/ufund-ui/public/delete.png b/ufund-ui/public/delete.png
deleted file mode 100644
index 6403705..0000000
--- a/ufund-ui/public/delete.png
+++ /dev/null
Binary files differ
diff --git a/ufund-ui/public/edit.png b/ufund-ui/public/edit.png
deleted file mode 100644
index 3b6e2d8..0000000
--- a/ufund-ui/public/edit.png
+++ /dev/null
Binary files differ
diff --git a/ufund-ui/public/jf.png b/ufund-ui/public/jf.png
new file mode 100644
index 0000000..bbf95d5
--- /dev/null
+++ b/ufund-ui/public/jf.png
Binary files differ
diff --git a/ufund-ui/public/search.png b/ufund-ui/public/search.png
deleted file mode 100644
index 1940ef5..0000000
--- a/ufund-ui/public/search.png
+++ /dev/null
Binary files differ
diff --git a/ufund-ui/src/app/app-routing.module.ts b/ufund-ui/src/app/app-routing.module.ts
index a6ea806..89b6f67 100644
--- a/ufund-ui/src/app/app-routing.module.ts
+++ b/ufund-ui/src/app/app-routing.module.ts
@@ -9,13 +9,13 @@ import {NeedPageComponent} from './components/need-page/need-page.component';
import {SignupComponent} from './components/signup/signup.component';
const routes: Routes = [
- {path: '', component: HomePageComponent},
- {path: 'login', component: LoginComponent},
- {path: 'cupboard', component: CupboardComponent},
- {path: 'dashboard', component: DashboardComponent},
- {path: 'basket', component: FundingBasketComponent},
- {path: 'need/:id', component: NeedPageComponent},
- {path: 'signup', component: SignupComponent},
+ { path: '', component: HomePageComponent, title: "Home | JS" },
+ { path: 'login', component: LoginComponent, title: "Login | JS" },
+ { path: 'cupboard', component: CupboardComponent, title: "Cupboard | JS" },
+ { path: 'dashboard', component: DashboardComponent, title: "Dashboard | JS" },
+ { path: 'basket', component: FundingBasketComponent, title: "Basket | JS" },
+ { path: 'need/:id', component: NeedPageComponent, title: "Need | JS" },
+ { path: 'signup', component: SignupComponent, title: "Signup | JS" },
];
@NgModule({
diff --git a/ufund-ui/src/app/app.component.css b/ufund-ui/src/app/app.component.css
index e69de29..0bcd658 100644
--- a/ufund-ui/src/app/app.component.css
+++ b/ufund-ui/src/app/app.component.css
@@ -0,0 +1,66 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+#header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ /*border-bottom: light-dark(#d3d3d3, black) solid 1px;*/
+ padding: 15px 20px;
+ /*background-color: light-dark(#f5f5f5, #2e2e2e);*/
+ z-index: 2;
+
+ h1 {
+ padding: 0;
+ margin: 0;
+ font-weight: 500;
+ /*text-decoration: none;*/
+ text-transform: uppercase;
+ font-size: 16pt;
+ letter-spacing: .5px;
+ }
+
+ div {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ }
+
+ /*div:has(a:hover) a {*/
+ /* color: light-dark(black, rgba(255, 255, 255, 0.5));*/
+ /*}*/
+
+ a {
+ color: light-dark(black, white);
+ text-decoration: none;
+ }
+
+ a {
+ display: block;
+ position: relative;
+ padding: 0.1em 0;
+ }
+
+ a::after {
+ content: '';
+ position: absolute;
+ bottom: 4px;
+ left: 0;
+ width: 100%;
+ height: 0.03em;
+ background-color: white;
+ opacity: 0;
+ transition: opacity 300ms, transform 300ms;
+ }
+
+ a:hover::after,
+ a:focus::after {
+ opacity: 1;
+ transform: translate3d(0, 0.2em, 0);
+ }
+
+
+}
diff --git a/ufund-ui/src/app/app.component.html b/ufund-ui/src/app/app.component.html
index a490237..959eada 100644
--- a/ufund-ui/src/app/app.component.html
+++ b/ufund-ui/src/app/app.component.html
@@ -1,6 +1,17 @@
-
-<h1>jelly solutions</h1>
-<span>{{currentUser$ | async}}</span> <br> <button *ngIf="currentUser$.value != 'Logged out.'" (click)="reloadPage()"> Log Out</button>
-<hr>
+<div id="header">
+ <div>
+ <a routerLink="/">
+ <h1>Jelly Solutions</h1>
+ </a>
+ </div>
+ <div>
+ <a routerLink="/dashboard">Dashboard</a>
+ <a routerLink="/cupboard">Cupboard</a>
+ <a routerLink="/basket">Basket</a>
+<!-- <span>{{currentUser$ | async}}</span>-->
+ <button *ngIf="currentUser | async" (click)="logout()"> Log Out</button>
+ <button *ngIf="!(currentUser | async)" (click)="login()"> Log In</button>
+ </div>
+</div>
<router-outlet />
diff --git a/ufund-ui/src/app/app.component.ts b/ufund-ui/src/app/app.component.ts
index 86717c4..2f98334 100644
--- a/ufund-ui/src/app/app.component.ts
+++ b/ufund-ui/src/app/app.component.ts
@@ -1,7 +1,10 @@
-import {Component, OnInit, Inject} from '@angular/core';
+import {Component, OnInit, Inject, ViewContainerRef} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import { DOCUMENT } from '@angular/common';
import {AuthService} from './services/auth.service';
+import {ToastsService} from './services/toasts.service';
+import {User} from './models/User';
+import {ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-root',
@@ -11,10 +14,14 @@ import {AuthService} from './services/auth.service';
})
export class AppComponent implements OnInit {
// title = 'ufund-ui';
- currentUser$: BehaviorSubject<string> = new BehaviorSubject<string>("Logged out.");
+ currentUser?: BehaviorSubject<User | null>;
constructor(
private authService: AuthService,
+ private router: Router,
+ private route: ActivatedRoute,
+ protected toastService: ToastsService,
+ private viewContainerRef: ViewContainerRef,
@Inject(DOCUMENT) private document: Document
) {}
@@ -23,12 +30,22 @@ export class AppComponent implements OnInit {
}
ngOnInit() {
- this.authService.getCurrentUserSubject().subscribe(r => {
- this.currentUser$?.next(r
- ? "Logged in as " + r.username
- : "Logged out."
- )
- })
+ this.toastService.setRootViewContainerRef(this.viewContainerRef)
+ this.currentUser = this.authService.getCurrentUserSubject()
+ let data = localStorage.getItem("credential");
+ if (data) {
+ let dataParsed = JSON.parse(data)
+ this.authService.restoreLogin(dataParsed.username, dataParsed.key)
+ console.log("Key found", dataParsed.key)
+ }
}
+ login() {
+ this.router.navigate(['/login'], {queryParams: {redir: this.router.url}});
+ }
+
+ logout() {
+ localStorage.removeItem("credential")
+ location.reload()
+ }
}
diff --git a/ufund-ui/src/app/app.module.ts b/ufund-ui/src/app/app.module.ts
index 156ef5f..c91256e 100644
--- a/ufund-ui/src/app/app.module.ts
+++ b/ufund-ui/src/app/app.module.ts
@@ -14,7 +14,9 @@ import {RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router';
import {DashboardComponent} from './components/dashboard/dashboard.component';
import {CommonModule} from '@angular/common';
import {LoginComponent} from './components/login/login.component';
+import { MiniNeedListComponent } from './components/mini-need-list/mini-need-list.component';
import { SignupComponent } from './components/signup/signup.component';
+import { ToastComponent } from './components/toast/toast.component';
@NgModule({
declarations: [
@@ -27,6 +29,8 @@ import { SignupComponent } from './components/signup/signup.component';
DashboardComponent,
LoginComponent,
SignupComponent,
+ MiniNeedListComponent,
+ ToastComponent,
],
imports: [
BrowserModule,
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.css b/ufund-ui/src/app/components/cupboard/cupboard.component.css
index 6e70951..faff4d4 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.css
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.css
@@ -1,20 +1,19 @@
:host {
display: flex;
- justify-content: space-evenly;
- border: 2px solid #000;
- border-radius: 5px;
- padding: 10px 20px;
- > div {
- width: 40%;
- }
+ justify-content: center;
}
+#box {
+ width: 1000px;
+ display: flex;
+ flex-direction: column;
+}
#menu {
display: flex;
-
+
margin: 10px;
-
+
}
.tab, .selected-tab {
@@ -34,10 +33,10 @@
background-color: #d9d9d9;
padding: 10px 20px 20px 20px;
border: 2px solid #000;
- border-radius: 5px;
+ border-radius: 5px;
visibility: visible;
}
#create-button {
padding: 10px 20px;
-} \ No newline at end of file
+}
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.html b/ufund-ui/src/app/components/cupboard/cupboard.component.html
index bc5ac1c..855bd7e 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.html
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.html
@@ -1,4 +1,4 @@
-<div>
+<div id="box">
<h1> Cupboard </h1>
<app-need-list (currentNeed) = populateForm($event) #needList></app-need-list>
</div>
@@ -13,6 +13,8 @@
<form #cupboardForm="ngForm" (ngSubmit)="submit(cupboardForm.value)">
<label>Name:</label><br>
<input type="text" name="name" ngModel><br>
+ <label>Image:</label><br>
+ <input type="text" name="image" ngModel><br>
<label>Location:</label><br>
<input type="text" name="location" ngModel><br>
<label>Max Goal:</label><br>
@@ -24,8 +26,10 @@
<label>Physical</label><br>
<input type="checkbox" name="urgent" value="false" ngModel>
<label>Urgent</label><br>
+ <label>Description</label>
+ <textarea name="description" [(ngModel)]="selectedNeed.description"></textarea><br>
<input type="submit" value="Submit">
-
+
</form>
<span *ngIf="statusText">{{statusText | async}}</span>
@@ -35,6 +39,7 @@
<label>Needs:</label><br>
<form #updateForm="ngForm" (ngSubmit)="update(updateForm.value)">
<input type="text" name="name" [(ngModel)]="selectedNeed.name"><br>
+ <input type="text" name="image" [(ngModel)]="selectedNeed.image"><br>
<input type="text" name="location" [(ngModel)]="selectedNeed.location"><br>
<label>Max Goal:</label><br>
<input type="number" name="maxGoal" [(ngModel)]="selectedNeed.maxGoal"><br>
@@ -45,8 +50,10 @@
<label>Physical</label><br>
<input type="checkbox" name="urgent" [(ngModel)]="selectedNeed.urgent">
<label>Urgent</label> <br>
+ <label>Description</label> <br>
+ <textarea name="description" [(ngModel)]="selectedNeed.description"></textarea><br>
<input type="submit" value="Submit">
-
+
</form>
<span *ngIf="statusText">{{statusText | async}}</span>
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.ts b/ufund-ui/src/app/components/cupboard/cupboard.component.ts
index 88ab46c..fff8760 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.ts
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.ts
@@ -2,9 +2,10 @@ import {Component, OnInit, ViewChild} from '@angular/core';
import { CupboardService } from '../../services/cupboard.service';
import { Need, GoalType } from '../../models/Need';
import { userType } from '../../models/User';
-import { BehaviorSubject, catchError, of } from 'rxjs';
+import { catchError, of } from 'rxjs';
import { NeedListComponent } from '../need-list/need-list.component';
import {AuthService} from '../../services/auth.service';
+import {ToastsService, ToastType} from '../../services/toasts.service';
@Component({
selector: 'app-cupboard',
@@ -15,14 +16,14 @@ import {AuthService} from '../../services/auth.service';
export class CupboardComponent implements OnInit {
- protected statusText = new BehaviorSubject("")
selectedForm = "create";
needs: any;
@ViewChild("needList") needList?: NeedListComponent
constructor(
private cupboardService: CupboardService,
- private authService: AuthService
+ private authService: AuthService,
+ private toastService: ToastsService
) {}
ngOnInit(): void {
@@ -85,23 +86,25 @@ export class CupboardComponent implements OnInit {
console.log(form);
const need: Need = {
name: form.name,
+ image: form.image,
location: form.location,
id: this.selectedNeed.id, //system will control this
maxGoal: form.maxGoal,
type: GoalType[form.type as keyof typeof GoalType],
urgent: form.urgent,
filterAttributes: [],
- current: 0
+ current: 0,
+ description: form.description
};
this.cupboardService.updateNeed(need.id, need)
.pipe(catchError((ex, _) => {
if (ex.status == 500) {
- this.statusText.next("Fields cannot be blank");
+ this.toastService.sendToast(ToastType.INFO, 'Fields cannot be blank');
} else if (ex.status == 400) {
- this.statusText.next(ex.error);
+ this.toastService.sendToast(ToastType.INFO, ex.error);
} else {
- this.statusText.next("Error on creating need");
+ this.toastService.sendToast(ToastType.INFO, "Error on creating need");
}
return of()
}))
@@ -121,24 +124,26 @@ export class CupboardComponent implements OnInit {
submit(form: any) {
const need: Need = {
name: form.name,
+ image: form.image,
location: form.location,
id: 0,
maxGoal: form.maxGoal,
type: form.type,
urgent: form.urgent ? true : false,
filterAttributes: [],
- current: 0
+ current: 0,
+ description: form.description
};
console.log("need:", need);
console.log("form submitted. creating need: ", need);
this.cupboardService.createNeed(need)
.pipe(catchError((ex, _) => {
if (ex.status == 500) {
- this.statusText.next("Fields cannot be blank");
+ this.toastService.sendToast(ToastType.INFO, "Fields cannot be blank");
} else if (ex.status == 400) {
- this.statusText.next(ex.error);
+ this.toastService.sendToast(ToastType.INFO, ex.error);
} else {
- this.statusText.next("Error on creating need");
+ this.toastService.sendToast(ToastType.INFO, "Error on creating need");
}
return of()
}))
diff --git a/ufund-ui/src/app/components/dashboard/dashboard.component.css b/ufund-ui/src/app/components/dashboard/dashboard.component.css
index e69de29..78a69ba 100644
--- a/ufund-ui/src/app/components/dashboard/dashboard.component.css
+++ b/ufund-ui/src/app/components/dashboard/dashboard.component.css
@@ -0,0 +1,7 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ width: 1000px;
+ align-self: center;
+ gap: 20px
+}
diff --git a/ufund-ui/src/app/components/dashboard/dashboard.component.html b/ufund-ui/src/app/components/dashboard/dashboard.component.html
index a1151b7..330d1f3 100644
--- a/ufund-ui/src/app/components/dashboard/dashboard.component.html
+++ b/ufund-ui/src/app/components/dashboard/dashboard.component.html
@@ -1,4 +1,5 @@
-<h1>Dashboard</h1>
-<app-cupboard></app-cupboard>
-<app-funding-basket *ngIf="!isManager()"></app-funding-basket> \ No newline at end of file
+<h1>Your Dashboard</h1>
+<app-mini-need-list [needList]="topNeeds" jtitle="Top needs" url="/cupboard"/>
+<app-mini-need-list [needList]="almostThere" jtitle="Almost there" url="/cupboard"/>
+<app-mini-need-list [needList]="inBasket" jtitle="In your basket" url="/cupboard"/>
diff --git a/ufund-ui/src/app/components/dashboard/dashboard.component.ts b/ufund-ui/src/app/components/dashboard/dashboard.component.ts
index a0ad566..645893f 100644
--- a/ufund-ui/src/app/components/dashboard/dashboard.component.ts
+++ b/ufund-ui/src/app/components/dashboard/dashboard.component.ts
@@ -1,6 +1,9 @@
-import {Component} from '@angular/core';
-import {userType} from '../../models/User';
+import {Component, OnInit} from '@angular/core';
import {AuthService} from '../../services/auth.service';
+import {Router} from '@angular/router';
+import {Need} from '../../models/Need';
+import {CupboardService} from '../../services/cupboard.service';
+import {firstValueFrom} from 'rxjs';
@Component({
selector: 'app-dashboard',
@@ -8,14 +11,30 @@ import {AuthService} from '../../services/auth.service';
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.css'
})
-export class DashboardComponent {
+export class DashboardComponent implements OnInit{
+
+ topNeeds?: Need[]
+ almostThere?: Need[]
+ inBasket?: Need[]
+
constructor(
protected authService: AuthService,
+ protected router: Router,
+ protected cupboardService: CupboardService
) {}
- isManager() {
- const type = this.authService.getCurrentUser()?.type;
- return type === ("MANAGER" as unknown as userType);
+ ngOnInit() {
+ let user = this.authService.getCurrentUser()
+ if(!localStorage.getItem("credential") && !user) {
+ this.router.navigate(['/login'])
+ return
+ }
+
+ firstValueFrom(this.cupboardService.getNeeds()).then(r => {
+ this.topNeeds = r.sort((a, b) => b.current - a.current)
+ this.almostThere = r.sort((a, b) => a.current/a.maxGoal - b.current/b.maxGoal)
+ this.inBasket = r.filter(n => n.id in user!.basket)
+ })
}
}
diff --git a/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts b/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts
index faa7e0b..24e2c0b 100644
--- a/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts
+++ b/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts
@@ -4,6 +4,7 @@ import {Router} from '@angular/router';
import {CupboardService} from '../../services/cupboard.service';
import {catchError, firstValueFrom, Observable} from 'rxjs';
import {AuthService} from '../../services/auth.service';
+import {ToastsService, ToastType} from '../../services/toasts.service';
@Component({
selector: 'app-funding-basket',
@@ -18,7 +19,8 @@ export class FundingBasketComponent implements OnInit {
private router: Router,
protected cupboardService: CupboardService,
protected usersService: UsersService,
- private authService: AuthService
+ private authService: AuthService,
+ private toastService: ToastsService
) {}
@ViewChild("contribution") contribution?: Input;
@@ -42,9 +44,20 @@ export class FundingBasketComponent implements OnInit {
contribution.setAttribute("style", "");
if (contribution.value == '' || contribution.valueAsNumber <= 0) {
this.isValid = false;
+
contribution.setAttribute("style", "color: #ff0000");
+ this.toastService.sendToast(ToastType.WARNING, "Invalid input in funding basket!")
}
}
+ // if (this.usersService.getBasket().value != await firstValueFrom(this.usersService.getUser(1))
+ // for (let c of this.usersService.getBasket().value) {
+ // if (c == null) {
+ // this.isValid = false;
+ // this.statusText.next("One or more needs have been deleted")
+ // } else {
+ // this.statusText.next("test")
+ // }
+ // }
if (this.isValid) {
for (let c of document.getElementById("funding-basket")?.querySelectorAll('.contribution')!) {
let contribution = c as HTMLInputElement;
@@ -54,11 +67,11 @@ export class FundingBasketComponent implements OnInit {
this.cupboardService.checkoutNeed(need.id, +contribution.value)
.pipe(catchError((ex, _) => {
if (ex.status == 500) {
- this.statusText.next('Fields cannot be blank');
+ this.toastService.sendToast(ToastType.INFO, 'Fields cannot be blank');
} else if (ex.status == 400) {
- this.statusText.next('Goal must be greater than 0');
+ this.toastService.sendToast(ToastType.INFO, 'Goal must be greater than 0');
} else {
- this.statusText.next('Error on creating need');
+ this.toastService.sendToast(ToastType.INFO, 'Error on creating need');
}
return new Observable<string>();
}))
diff --git a/ufund-ui/src/app/components/home-page/home-page.component.css b/ufund-ui/src/app/components/home-page/home-page.component.css
index e69de29..16f3140 100644
--- a/ufund-ui/src/app/components/home-page/home-page.component.css
+++ b/ufund-ui/src/app/components/home-page/home-page.component.css
@@ -0,0 +1,37 @@
+:host {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+#hero {
+ display: flex;
+ /*flex-direction: column;*/
+ /*align-items: start;*/
+ /*justify-content: center;*/
+}
+
+h1 {
+ font-size: 50px;
+ max-width: 1200px;
+}
+
+#jf {
+ /*position: absolute;*/
+}
+
+#right {
+ max-width: 500px;
+ max-height: 500px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ /*z-index: -0.5;*/
+}
+
+#left {
+ max-width: 500px;
+ z-index: 1;
+}
diff --git a/ufund-ui/src/app/components/home-page/home-page.component.html b/ufund-ui/src/app/components/home-page/home-page.component.html
index d41e670..7a7ff96 100644
--- a/ufund-ui/src/app/components/home-page/home-page.component.html
+++ b/ufund-ui/src/app/components/home-page/home-page.component.html
@@ -1,3 +1,10 @@
-<a routerLink="/login">
- Login/Sign Up
-</a> \ No newline at end of file
+<div id="hero">
+ <div id="left">
+ <h1>Helping fund coral reef and marine life conservation</h1>
+ <p>View our online cupboard holding all needs related to sea life preservation</p>
+ <button class="button2" routerLink="/cupboard">View needs</button>
+ </div>
+ <div id="right">
+ <img id="jf" src="jf.png" height="1024" width="1024"/>
+ </div>
+</div>
diff --git a/ufund-ui/src/app/components/login/login.component.css b/ufund-ui/src/app/components/login/login.component.css
index 435cc87..b56b4eb 100644
--- a/ufund-ui/src/app/components/login/login.component.css
+++ b/ufund-ui/src/app/components/login/login.component.css
@@ -1,8 +1,28 @@
-:host, .border {
- display: flex;
- flex-direction: column;
- max-width: 300px;
- gap: 5px
+:host {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ /*background-image: url("https://www.fineshare.com/background/jellyfish-under-fluorescent-illumination.jpg");*/
+ background: rgba(0, 0, 0, .65) url("https://4kwallpapers.com/images/wallpapers/blue-jellyfish-aquarium-underwater-glowing-marine-life-1920x1080-3546.jpg");
+ background-blend-mode: darken;
+ margin-top: -66px
+
+}
+
+#box {
+ display: flex;
+ flex-direction: column;
+ max-width: 350px;
+ gap: 10px;
+ backdrop-filter: blur(10px);
+ background-color: rgba(0, 0, 0, 0.1);
+ padding: 30px;
+ color: white;
+ border-radius: 5px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(140, 140, 255);
}
.border {
diff --git a/ufund-ui/src/app/components/login/login.component.html b/ufund-ui/src/app/components/login/login.component.html
index a6441f4..e1c3e2a 100644
--- a/ufund-ui/src/app/components/login/login.component.html
+++ b/ufund-ui/src/app/components/login/login.component.html
@@ -1,7 +1,10 @@
-<span *ngIf="next" style="color: red">You must be logged in to view this page</span>
-<p>Login:</p>
-<input placeholder="Username" type="text" #username>
-<input placeholder="Password" type="password" #password>
-<button type="button" (click)="login(username.value, password.value)">Login</button>
-<button type="button" routerLink="/signup">Create Account...</button>
-<span *ngIf="statusText">{{statusText | async}}</span>
+<div id="box">
+ <h1>Login</h1>
+ <input placeholder="Username" type="text" #username>
+ <input placeholder="Password" type="password" #password>
+ <button type="button" (click)="login(username.value, password.value)">Login</button>
+ <div>
+ New? <a routerLink="/signup">Create an account</a>
+ </div>
+ <span *ngIf="statusText">{{statusText | async}}</span>
+</div>
diff --git a/ufund-ui/src/app/components/login/login.component.ts b/ufund-ui/src/app/components/login/login.component.ts
index f6a2996..0177f67 100644
--- a/ufund-ui/src/app/components/login/login.component.ts
+++ b/ufund-ui/src/app/components/login/login.component.ts
@@ -1,8 +1,8 @@
import {Component, OnInit} from '@angular/core'
import {UsersService} from '../../services/users.service';
import {ActivatedRoute, Router} from '@angular/router';
-import {BehaviorSubject} from 'rxjs';
import {AuthService} from '../../services/auth.service';
+import {ToastsService, ToastType} from '../../services/toasts.service';
@Component({
selector: 'app-login',
@@ -13,13 +13,13 @@ import {AuthService} from '../../services/auth.service';
export class LoginComponent implements OnInit {
protected next?: string | null;
- protected statusText = new BehaviorSubject("")
constructor(
protected usersService: UsersService,
protected router: Router,
private route: ActivatedRoute,
- private authService: AuthService
+ private authService: AuthService,
+ private toastService: ToastsService
) {}
ngOnInit() {
@@ -35,8 +35,10 @@ export class LoginComponent implements OnInit {
this.authService.login(username, password).then(() => {
this.router.navigate([next]);
+ let key = this.authService.getApiKey()
+ localStorage.setItem("credential", JSON.stringify({username: username, key: key}))
}).catch(ex => {
- this.statusText.next("Unable to login: " + friendlyHttpStatus[ex.status])
+ this.toastService.sendToast(ToastType.ERROR, "Unable to login: " + friendlyHttpStatus[ex.status])
console.log(ex)
})
}
@@ -48,9 +50,9 @@ export class LoginComponent implements OnInit {
}
this.usersService.createUser(username, password).then(() => {
- this.statusText.next("Account created, click login.")
+ this.toastService.sendToast(ToastType.INFO, "Account created, click login.")
}).catch(ex => {
- this.statusText.next("Unable to create account: " + friendlyHttpStatus[ex.status])
+ this.toastService.sendToast(ToastType.ERROR, "Unable to create account: " + friendlyHttpStatus[ex.status])
console.log(ex)
})
}
diff --git a/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.css b/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.css
new file mode 100644
index 0000000..ac456ab
--- /dev/null
+++ b/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.css
@@ -0,0 +1,56 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ border: solid rgba(255, 255, 255, 0.5) 1px;
+ border-radius: 5px;
+}
+
+#header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ border-bottom: solid rgba(255, 255, 255, 0.5) 1px;
+ padding: 10px;
+
+ a {
+ display: flex;
+ }
+}
+
+#needList {
+ display: flex;
+ flex-direction: row;
+ padding: 10px;
+ gap: 10px;
+ justify-content: start;
+ overflow: clip;
+}
+
+.needEntry {
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ background-color: #3a3a3a;
+ border-radius: 5px;
+ height: 175px;
+ width: 200px;
+ justify-content: space-between;
+
+ div {
+ display: flex;
+ flex-direction: column;
+ }
+
+ user-select: none;
+ cursor: pointer;
+}
+
+.needName {
+ font-weight: bold;
+}
+
+.needType {
+ text-transform: uppercase;
+ /*font-weight: 300;*/
+ font-size: 10pt;
+}
diff --git a/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.html b/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.html
new file mode 100644
index 0000000..a2de9e5
--- /dev/null
+++ b/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.html
@@ -0,0 +1,17 @@
+<div id="header">
+ <span>{{jtitle}}</span>
+ <a [routerLink]="url">Show All<span class="icon">arrow_forward_ios</span></a>
+</div>
+
+<div id="needList">
+ <div class="needEntry" *ngFor="let need of needList" [routerLink]="'/need/'+need.id">
+ <div>
+ <span class="needName">{{need.name}}</span>
+ <span class="needType">{{need.type}}</span>
+ </div>
+ <div>
+ <span>{{need.current}}/{{need.maxGoal}}</span>
+ <progress [max]="need.maxGoal" [value]="need.current"></progress>
+ </div>
+ </div>
+</div>
diff --git a/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.ts b/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.ts
new file mode 100644
index 0000000..c909ae6
--- /dev/null
+++ b/ufund-ui/src/app/components/mini-need-list/mini-need-list.component.ts
@@ -0,0 +1,19 @@
+import {Component, Input} from '@angular/core';
+import {Need} from '../../models/Need';
+
+@Component({
+ selector: 'app-mini-need-list',
+ standalone: false,
+ templateUrl: './mini-need-list.component.html',
+ styleUrl: './mini-need-list.component.css'
+})
+export class MiniNeedListComponent {
+
+ @Input() needList?: Need[]
+ @Input() jtitle?: string
+ @Input() url?: string
+
+ constructor(
+
+ ) {}
+}
diff --git a/ufund-ui/src/app/components/need-list/need-list.component.css b/ufund-ui/src/app/components/need-list/need-list.component.css
index 345326f..1936b38 100644
--- a/ufund-ui/src/app/components/need-list/need-list.component.css
+++ b/ufund-ui/src/app/components/need-list/need-list.component.css
@@ -1,82 +1,85 @@
-:host {
- --list-background-color: lightgray;
- list-style-type: none;
- border: 2px solid #000;
- display: block;
- border-radius: 5px;
+#header {
+ display: flex;
+ flex-direction: column;
+ gap: 10px
}
-div {
- border: 2px solid #000;
+.needEntry {
+ background-color: #3a3a3a;
+ display: flex;
+ flex-direction: column;
border-radius: 5px;
- padding: 5px;
- margin: 5px;
+ padding: 10px;
}
-ul {
- list-style-type: none;
- padding-inline-start: 0px;
+#needList {
+ display: flex;
+ flex-direction: column;
+ gap: 10px
}
-li {
- background-color: var(--list-background-color);
+select {
+ font-size: 14pt;
+ padding: 5px;
+}
+
+#searchArea {
display: flex;
- justify-content: space-between;
- align-items: center;
- transition: all 0.3s ease;
- font-weight: bold;
- border: 2px solid #000;
- border-radius: 5px;
- margin: 5px;
- > button {
- background-color: transparent;
- width: 88%;
- transition: all 0.3s ease;
- font-weight: bold;
- border: none;
- border-radius: 5px;
- padding-left: 1.5%;
- > section {
- width: 100%;
- flex: none;
- display: inline-block;
- background-color: magenta;
- > progress {
- width: 25%;
- float: none;
- }
- }
+
+ form {
+ display: flex;
+ width: 100%;
+ gap: 10px;
}
- > section {
- width: 12%;
+ input[type=text] {
+ display: flex;
+ width: 100%;
}
}
-section button{
- margin: 4%;
+#sortArea {
+ display: flex;
+ flex-direction: row;
+ gap: 10px;
+ align-items: center;
}
-li > button span {
- font-style: italic;
- font-weight: normal;
+.needName {
+ font-weight: bold;
}
-li > button:hover p {
- text-decoration: underline;
+.needType {
+ text-transform: uppercase;
+ font-size: 10pt;
}
+.split {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+
+ .left {
+ display: flex;
+ flex-direction: column;
+ }
-.icon {
- width: 18px;
- margin: 3px -3px -1px -3px;
+ .right {
+ display: flex;
+ flex-direction: column;
+ align-items: end;
+ }
}
-#search-container {
- background-color: #d9d9d9;
- border: 2px solid #000;
+.urgent {
+ font-size: 11pt;
+ background-color: rgba(255, 165, 0, 0.27);
+ color: rgba(255, 165, 0, 1);
+ padding: 2px;
border-radius: 5px;
- .wide-input {
- width: 60%;
- }
- } \ No newline at end of file
+}
+
+.prog {
+ display: flex;
+ flex-direction: column;
+}
diff --git a/ufund-ui/src/app/components/need-list/need-list.component.html b/ufund-ui/src/app/components/need-list/need-list.component.html
index 866e5e4..c325320 100644
--- a/ufund-ui/src/app/components/need-list/need-list.component.html
+++ b/ufund-ui/src/app/components/need-list/need-list.component.html
@@ -1,22 +1,21 @@
-<h1>Needs List</h1>
-<div id="search-container">
- <section>
+<div id="header">
+ <div id="searchArea">
+ <form id="search-form" #searchForm="ngForm">
+ <input type="text" name="search" class="wide-input" placeholder="Search in {{needs.length}} needs..." (input)="search(searchForm.value)" ngModel>
+ <input type="reset" value="Clear" (click)="search(null)"> <br>
+ </form>
+ </div>
+ <div id="sortArea">
<label for="sort">Sort by: </label>
- <select [(ngModel)] = "sortSelection" class="wide-input" (change)="search(searchForm.value)" [value]="sortSelection">
+ <select id='sort' [(ngModel)] = "sortSelection" class="wide-input" (change)="search(searchForm.value)" [value]="sortSelection">
<option *ngFor="let algorithm of SortingAlgoArrays" value="{{algorithm.name}}">
{{algorithm.display[sortMode === 'Ascending' ? 0 : 1]}}
</option>
</select>
<button (click)="changeSortMode(searchForm.value)">
- {{sortMode}}
+ <span class="icon">{{sortMode === 'Ascending' ? 'arrow_upward': 'arrow_downward'}}</span>
</button>
- </section>
- <section>
- <form id="search-form" #searchForm="ngForm">
- <input type="text" name="search" class="wide-input" placeholder="Search in {{needs.length}} needs..." (input)="search(searchForm.value)" ngModel>
- <input type="reset" value="Clear" (click)="search(null)"> <br>
- </form>
- </section>
+ </div>
<!--<button (click)="close()">Close</button>-->
</div>
@@ -25,27 +24,40 @@
<h2 *ngIf="searchResults.length == needs.length"> All Needs </h2>
<h2 *ngIf="searchResults.length == 0"> No Results Found </h2>
-<ul>
- <li *ngFor="let need of searchResults" id="need-button-{{need.id}}">
- <button [routerLink]="'/need/' + need.id" (mouseenter) ="changeText(need.id, '(details)')" (mouseleave)="changeText(need.id, '')">
- <section> <p> {{need.name}} | {{need.location}} <span> {{need.urgent ? "URGENT" : ""}} </span> <span id="hover-status-label-{{need.id}}"> </span> </section>
- <section>
- <progress value="need.current" max="need.maxGoal"></progress>
- <progress value="need.current" max="need.maxGoal"></progress>
- <progress value="need.current" max="need.maxGoal"></progress>
- <progress value="need.current" max="need.maxGoal"></progress>
- </section>
- <section>{{need.current}}/{{need.maxGoal}} {{(need.current / need.maxGoal) * 100}}% <span>{{need.type}}</span></section>
- </button>
+<div id="needList">
+ <div *ngFor="let need of searchResults" class="needEntry">
+ <div [routerLink]="'/need/' + need.id">
+ <div class="split">
+ <div class="left">
+ <span class="needName">{{need.name}}</span>
+ <span class="needType">{{need.type}}</span>
+ </div>
+
+ <div class="right">
+ <span *ngIf="need.urgent" class="urgent">URGENT</span>
+ <span *ngIf="need.location"><span class="icon">location_on</span>{{need.location}}</span>
+ </div>
+ </div>
+
+ <div class="prog">
+ <span id="hover-status-label-{{need.id}}"> </span>
+ <span>{{need.current}}/{{need.maxGoal}} ({{((need.current / need.maxGoal) * 100).toFixed(0)}}%)</span>
+ <progress [value]="need.current" [max]="need.maxGoal"></progress>
+ </div>
- <button (click)="add(need)" *ngIf="isHelper()">Add To Basket</button>
- <section *ngIf="isManager()">
- <button (click)="select(need)" id="need-edit-button-{{need.id}}">
- <img class="icon" src="/edit.png" alt="Select">
+ <div class="description">
+ {{need.description}}
+ </div>
+ </div>
+
+ <div>
+ <button *ngIf="isHelper()" (click)="add(need)">Add To Basket</button>
+ <button *ngIf="isManager()" (click)="select(need)">
+ <span class="icon">edit</span>
</button>
- <button (click)="delete(need.id)" *ngIf="isManager()">
- <img class="icon" src="/delete.png" alt="Delete">
+ <button *ngIf="isManager()" (click)="delete(need.id)" >
+ <span class="icon">delete</span>
</button>
- </section>
- </li>
-</ul> \ No newline at end of file
+ </div>
+ </div>
+</div>
diff --git a/ufund-ui/src/app/components/need-list/need-list.component.ts b/ufund-ui/src/app/components/need-list/need-list.component.ts
index af8cab4..47114c3 100644
--- a/ufund-ui/src/app/components/need-list/need-list.component.ts
+++ b/ufund-ui/src/app/components/need-list/need-list.component.ts
@@ -66,7 +66,7 @@ export class NeedListComponent {
selectedNeed: Need | null = null;
needs: Need[] = [];
searchResults: Need[] = [];
- sortMode = 'Ascending'
+ sortMode: 'Ascending' | 'Descending' = 'Ascending'
currentSortAlgo: sortAlgo = sortByPriority;
sortSelection: string = 'sortByPriority';
@@ -98,7 +98,7 @@ export class NeedListComponent {
});
const form = document.getElementById('search-form') as HTMLFormElement;
- form.reset();
+ form.reset();
this.search(null);
}
diff --git a/ufund-ui/src/app/components/need-page/need-page.component.css b/ufund-ui/src/app/components/need-page/need-page.component.css
index e69de29..a3a4014 100644
--- a/ufund-ui/src/app/components/need-page/need-page.component.css
+++ b/ufund-ui/src/app/components/need-page/need-page.component.css
@@ -0,0 +1,10 @@
+:host {
+ display: flex;
+ justify-content: center;
+}
+
+#box {
+ display: flex;
+ flex-direction: column;
+ width: 1000px;
+}
diff --git a/ufund-ui/src/app/components/need-page/need-page.component.html b/ufund-ui/src/app/components/need-page/need-page.component.html
index 004f9eb..a72167c 100644
--- a/ufund-ui/src/app/components/need-page/need-page.component.html
+++ b/ufund-ui/src/app/components/need-page/need-page.component.html
@@ -1,23 +1,26 @@
-<button routerLink="/dashboard">Back to dashboard</button>
-<h1>Viewing Need: {{need?.name}}</h1>
-<a>internal id: {{need?.id}}</a>
-<div style="display: flex; column-gap: 6px;">
- <h3>Looking for</h3>
- <h3><u>{{need?.type}}</u></h3>
- <h3>Donations.</h3>
-</div>
-<div *ngIf="need?.filterAttributes != null">
- <p>Tags:</p>
- <ul style="display: flex; column-gap: 24px;">
- <li *ngFor="let tag of need?.filterAttributes">
- <p>{{tag}}</p>
- </li>
- </ul>
-</div>
+<div id="box">
+ <h1>{{need?.name}}</h1>
+ <div>
+ <h3>Looking for <u>{{need?.type}}</u> Donations.</h3>
+ </div>
+ <div *ngIf="need?.filterAttributes">
+ <p>Tags:</p>
+ <ul style="display: flex; column-gap: 24px;">
+ <li *ngFor="let tag of need?.filterAttributes">
+ <p>{{tag}}</p>
+ </li>
+ </ul>
+ </div>
-<hr>
-<p>Location: {{need?.location}}</p>
-<p>Goal: {{need?.maxGoal}}</p>
-<p>Current: {{need?.current}}</p>
-<p>Urgent: {{need?.urgent}}</p>
-<p>This goal is <strong>{{(((need?.current ?? 0)*100) / (need?.maxGoal ?? 0)).toFixed(0)}}%</strong> complete!</p> \ No newline at end of file
+ <hr>
+ <p>Location: {{need?.location}}</p>
+ <p>Urgent: {{need?.urgent}}</p>
+ <span>{{need?.current}} / {{need?.maxGoal}}</span>
+ <progress [value]="need?.current" [max]="need?.maxGoal"></progress>
+ <span>This goal is <strong>{{(((need?.current ?? 0)*100) / (need?.maxGoal ?? 0)).toFixed(0)}}%</strong> complete!</span>
+ <div>
+ <button>Add to basket</button>
+ <button>Edit</button>
+ <button>Delete</button>
+ </div>
+</div>
diff --git a/ufund-ui/src/app/components/signup/signup.component.css b/ufund-ui/src/app/components/signup/signup.component.css
index f286cf9..429bc42 100644
--- a/ufund-ui/src/app/components/signup/signup.component.css
+++ b/ufund-ui/src/app/components/signup/signup.component.css
@@ -1,7 +1,16 @@
:host {
display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ margin-top: -66px
+
+}
+
+#box {
+ display: flex;
flex-direction: column;
- max-width: 300px;
+ /*max-width: 300px;*/
gap: 10px;
& > div {
@@ -45,3 +54,20 @@
color: red;
}
+#passReq {
+ display: flex;
+ flex-direction: column;
+}
+
+#box > div {
+ display: flex;
+ flex-direction: row;
+ align-items: start;
+ gap: 20px;
+
+ div {
+ display: flex;
+ flex-direction: column;
+ }
+}
+
diff --git a/ufund-ui/src/app/components/signup/signup.component.html b/ufund-ui/src/app/components/signup/signup.component.html
index ebedc2a..bc3aaf0 100644
--- a/ufund-ui/src/app/components/signup/signup.component.html
+++ b/ufund-ui/src/app/components/signup/signup.component.html
@@ -1,26 +1,31 @@
-<p>Signup:</p>
-<div>
- <input placeholder="Username" type="text" (input)="validate(username.value, confirmPass.value, password.value)" #username>
- <span *ngIf="usernameStatusText">{{usernameStatusText | async}}</span>
-</div>
+<div id="box">
+ <h1>Create an account</h1>
+ <div>
+ <input placeholder="Username" type="text" (input)="validate(username.value, confirmPass.value, password.value)" #username>
+ <span *ngIf="usernameStatusText">{{usernameStatusText | async}}</span>
+ </div>
-<div>
- <input placeholder="Password" type="password" (input)="validate(username.value, confirmPass.value, password.value)" #password>
- <progress [ngClass]="'color' + strength.getValue()" id="bar" [value]="strength | async" max="6"> </progress>
- <span *ngIf="passwordStatusText">{{passwordStatusText | async}}</span>
+ <div>
+ <div>
+ <input placeholder="Password" type="password" (input)="validate(username.value, confirmPass.value, password.value)" #password>
+ <progress [ngClass]="'color' + strength.getValue()" id="bar" [value]="strength | async" max="6"> </progress>
+ <span *ngIf="passwordStatusText">{{passwordStatusText | async}}</span>
+ </div>
- <span *ngFor="let requirement of Object.values(passwordRequirements)">
- <span *ngIf="passwordRequirements" [style.color]="requirement.value ? 'green' : 'red'"> {{requirement.title}} </span>
- </span>
-</div>
+ <div id="passReq">
+ <span *ngFor="let requirement of Object.values(passwordRequirements)" [style.color]="requirement.value ? 'green' : 'red'"><span class="icon">{{requirement.value?"check":"close"}}</span> {{requirement.title}}</span>
+ </div>
+ </div>
-<div>
- <input placeholder="Confirm password" type="password" (input)="validate(username.value, confirmPass.value, password.value)" #confirmPass>
- <span *ngIf="confirmPassStatusText">{{confirmPassStatusText | async}}</span>
-</div>
+ <div>
+ <input placeholder="Confirm password" type="password" (input)="validate(username.value, confirmPass.value, password.value)" #confirmPass>
+ <span [style.color]="(passwordsMatch|async) ? 'green' : 'red'" *ngIf="passwordsMatch"><span class="icon">{{(passwordsMatch|async)?"check":"close"}}</span> Passwords match</span>
+ </div>
-<div>
- <button [disabled]="!(ableToCreateAccount | async)" (click)="signup(username.value, password.value)">Create Account</button>
- <span *ngIf="showSuccessMessage | async">Account created <a routerLink="/login">Proceed to login</a></span>
- <span *ngIf="statusText | async">{{statusText | async}}</span>
+ <div>
+ <button [disabled]="!(ableToCreateAccount | async)" (click)="signup(username.value, password.value)">Create Account</button>
+ <span *ngIf="showSuccessMessage | async">Account created <a routerLink="/login">Proceed to login</a></span>
+ <span *ngIf="statusText | async">{{statusText | async}}</span>
+ </div>
+ <span>Already have an account? <a routerLink="/login">Log in</a></span>
</div>
diff --git a/ufund-ui/src/app/components/signup/signup.component.ts b/ufund-ui/src/app/components/signup/signup.component.ts
index 3b43287..5ec84ae 100644
--- a/ufund-ui/src/app/components/signup/signup.component.ts
+++ b/ufund-ui/src/app/components/signup/signup.component.ts
@@ -2,6 +2,7 @@ import {Component} from '@angular/core';
import {UsersService} from '../../services/users.service';
import {Router} from '@angular/router';
import {BehaviorSubject} from 'rxjs';
+import {ToastsService, ToastType} from '../../services/toasts.service';
class PasswordRequirements {
sixLong: {title: string, value: boolean} = {title: 'Is 6 characters or longer' , value: false}
@@ -22,7 +23,7 @@ class PasswordRequirements {
export class SignupComponent {
protected passwordStatusText = new BehaviorSubject("")
- protected confirmPassStatusText = new BehaviorSubject("")
+ protected passwordsMatch = new BehaviorSubject(false)
protected usernameStatusText = new BehaviorSubject("")
protected showSuccessMessage = new BehaviorSubject(false)
protected passwordStrongEnough = new BehaviorSubject(false)
@@ -34,6 +35,7 @@ export class SignupComponent {
constructor(
protected usersService: UsersService,
protected router: Router,
+ protected toastService: ToastsService
) {}
signup(username: string | null, password: string | null) {
@@ -45,13 +47,13 @@ export class SignupComponent {
this.usersService.createUser(username, password).then(() => {
this.showSuccessMessage.next(true);
}).catch(ex => {
- this.statusText.next("Unable to create account: " + friendlyHttpStatus[ex.status])
+ this.toastService.sendToast(ToastType.INFO, "Unable to create account: " + friendlyHttpStatus[ex.status])
console.log(ex)
})
}
validate(username: string, passConfirm:string, password: string) {
- this.confirmPassStatusText.next("")
+ this.passwordsMatch.next(false)
this.usernameStatusText.next("")
this.checkPasswordStrength(password);
@@ -59,8 +61,8 @@ export class SignupComponent {
this.usernameStatusText.next("Username field can't be blank")
}
- if (!(password === passConfirm) && !!passConfirm) {
- this.confirmPassStatusText.next("Passwords don't match")
+ if (passConfirm && password === passConfirm) {
+ this.passwordsMatch.next(true)
}
this.ableToCreateAccount.next(this.passwordStrongEnough.getValue() && password === passConfirm && !!username)
}
@@ -106,7 +108,7 @@ export class SignupComponent {
} else if (strength == 0) {
this.passwordStatusText.next("")
} else {
- this.passwordStatusText.next("Password does not meet requirements")
+ this.passwordStatusText.next("5/6 checks required")
}
this.strength.next(strength)
diff --git a/ufund-ui/src/app/components/toast/toast.component.css b/ufund-ui/src/app/components/toast/toast.component.css
new file mode 100644
index 0000000..4cd81fe
--- /dev/null
+++ b/ufund-ui/src/app/components/toast/toast.component.css
@@ -0,0 +1,57 @@
+:host {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+@keyframes slideDown {
+ from {transform: translateY(-90px);}
+ to {transform: translateY(0);}
+}
+
+.toast {
+ /*transform: translateY(-90px);*/
+ animation: slideDown .5s ease-in-out;
+ transition: transform .5s;
+ align-self: center;
+ z-index: 3;
+ position: absolute;
+ top: 15px;
+ display: flex;
+ flex-direction: row;
+ padding: 3px 15px;
+ background-color: #3a3a3a;
+ border-radius: 100000px;
+ gap: 10px;
+ align-items: center;
+
+ button {
+ aspect-ratio: 1/1;
+ margin-right: -11px;
+ padding: 8px;
+ display: flex;
+ align-items: center;
+ background-color: transparent;
+ }
+
+ button:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+ }
+}
+
+.toast.hide {
+ transform: translateY(-90px);
+}
+
+.toast.warning {
+ background-color: #ffc500;
+ color: black;
+
+ button {
+ color: black;
+ }
+}
+
+.toast.error {
+ background-color: #d81a1a;
+}
diff --git a/ufund-ui/src/app/components/toast/toast.component.html b/ufund-ui/src/app/components/toast/toast.component.html
new file mode 100644
index 0000000..dccf869
--- /dev/null
+++ b/ufund-ui/src/app/components/toast/toast.component.html
@@ -0,0 +1,7 @@
+<div class="toast" [ngClass]="ToastType[type].toLowerCase()" #toastDiv>
+ <span>{{this.message}}</span>
+ <a *ngIf="this.action" (click)="this.action.onAction()">{{this.action.label}}</a>
+ <button (click)="hide()">
+ <span class="icon">close</span>
+ </button>
+</div>
diff --git a/ufund-ui/src/app/components/toast/toast.component.ts b/ufund-ui/src/app/components/toast/toast.component.ts
new file mode 100644
index 0000000..47fd7ff
--- /dev/null
+++ b/ufund-ui/src/app/components/toast/toast.component.ts
@@ -0,0 +1,37 @@
+import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core';
+import {ToastType} from '../../services/toasts.service';
+
+@Component({
+ selector: 'app-toast',
+ standalone: false,
+ templateUrl: './toast.component.html',
+ styleUrl: './toast.component.css'
+})
+export class ToastComponent implements OnInit{
+ @Input() type!: ToastType
+ @Input() message!: string
+ @Input() action?: {label: string, onAction: () => void}
+
+ @ViewChild("toastDiv") toastDiv!: ElementRef<HTMLDivElement>
+
+ ngOnInit() {
+ setTimeout(() => {
+ this.hide();
+ }, 3000)
+ }
+
+ hide() {
+ console.log(this.toastDiv, typeof this.toastDiv)
+ this.toastDiv.nativeElement.classList.add('hide')
+ }
+
+ getColor() {
+ switch (this.type) {
+ case ToastType.ERROR: return "red";
+ case ToastType.INFO: return "";
+ case ToastType.WARNING: return "yellow";
+ }
+ }
+
+ protected readonly ToastType = ToastType;
+}
diff --git a/ufund-ui/src/app/models/Need.ts b/ufund-ui/src/app/models/Need.ts
index 1451cad..6cf7e76 100644
--- a/ufund-ui/src/app/models/Need.ts
+++ b/ufund-ui/src/app/models/Need.ts
@@ -1,5 +1,6 @@
export interface Need {
name: string,
+ image: string,
id: number,
filterAttributes: string[],
location: string;
@@ -7,6 +8,7 @@ export interface Need {
maxGoal: number;
current: number;
urgent: boolean;
+ description: string;
}
export enum GoalType {
diff --git a/ufund-ui/src/app/services/auth.service.ts b/ufund-ui/src/app/services/auth.service.ts
index 6bc7145..b75c931 100644
--- a/ufund-ui/src/app/services/auth.service.ts
+++ b/ufund-ui/src/app/services/auth.service.ts
@@ -1,7 +1,8 @@
-import {Injectable} from '@angular/core';
+import {Injectable, Injector} from '@angular/core';
import {BehaviorSubject, firstValueFrom} from 'rxjs';
import {User} from '../models/User';
import {HttpClient, HttpHeaders} from '@angular/common/http';
+import {UsersService} from './users.service';
@Injectable({
providedIn: 'root'
@@ -24,7 +25,9 @@ export class AuthService {
});
constructor(
- private http: HttpClient
+ private http: HttpClient,
+ // private userService: UsersService
+ private injector: Injector
) {}
async login(username: string, password: string) {
@@ -42,6 +45,13 @@ export class AuthService {
// this.currentUser.subscribe(r => console.log("currentUser: "+r.username))
}
+ async restoreLogin(username: string, key: string) {
+
+ const userService = this.injector.get(UsersService);
+ this.apiKey = key;
+ this.currentUser.next(await firstValueFrom(userService.getUser(username)))
+ }
+
getCurrentUserSubject() {
return this.currentUser;
}
diff --git a/ufund-ui/src/app/services/toasts.service.ts b/ufund-ui/src/app/services/toasts.service.ts
new file mode 100644
index 0000000..4fd024e
--- /dev/null
+++ b/ufund-ui/src/app/services/toasts.service.ts
@@ -0,0 +1,27 @@
+import {Injectable, ViewContainerRef} from '@angular/core';
+import {ToastComponent} from '../components/toast/toast.component';
+
+export enum ToastType {
+ INFO,
+ WARNING,
+ ERROR
+}
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ToastsService {
+
+ private vcr?: ViewContainerRef
+
+ sendToast(type: ToastType, message: string, action?: {label: string, onAction: () => void}) {
+ let compRef = this.vcr?.createComponent(ToastComponent)!
+ compRef.setInput("message", message)
+ compRef.setInput("type", type)
+ compRef.setInput("action", action)
+ }
+
+ setRootViewContainerRef(vcr: ViewContainerRef) {
+ this.vcr = vcr
+ }
+}
diff --git a/ufund-ui/src/index.html b/ufund-ui/src/index.html
index 0517d5e..b6ae1a2 100644
--- a/ufund-ui/src/index.html
+++ b/ufund-ui/src/index.html
@@ -1,13 +1,17 @@
<!doctype html>
<html lang="en">
<head>
- <meta charset="utf-8">
- <title>UfundUi</title>
- <base href="/">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="icon" type="image/x-icon" href="favicon.ico">
+ <meta charset="utf-8">
+ <title>UfundUi</title>
+ <base href="/">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
+ <link rel="preconnect" href="https://fonts.googleapis.com">
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+ <link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
+ <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
</head>
<body>
- <app-root></app-root>
+<app-root></app-root>
</body>
</html>
diff --git a/ufund-ui/src/styles.css b/ufund-ui/src/styles.css
index 90d4ee0..b152e61 100644
--- a/ufund-ui/src/styles.css
+++ b/ufund-ui/src/styles.css
@@ -1 +1,63 @@
/* You can add global styles to this file, and also import other style files */
+
+:root {
+ color-scheme: light dark;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html, body {
+ margin: 0;
+ height: 100%;
+ background-color: light-dark(white, #000715);
+}
+
+body {
+ font-family: Inter, sans-serif;
+ font-optical-sizing: auto;
+}
+
+input {
+ font-size: 14pt;
+ padding: 5px;
+ border-radius: 5px;
+ border-style: solid;
+ border-width: 1px;
+ background-color: light-dark(#ebebeb, #3a3a3a);
+
+ &:hover {
+ background-color: light-dark(#e1e1e1, #444444);
+ }
+}
+
+button, input[type=button], input[type=reset], input[type=submit], .button {
+ font-size: 14pt;
+ padding: 6px 16px;
+ border-radius: 9999px;
+ border-style: none;
+ background-color: light-dark(#ebebeb, #3a3a3a);
+
+ &:hover {
+ background-color: light-dark(#e1e1e1, #444444);
+ }
+}
+
+.button2 {
+ text-transform: uppercase;
+ border: 1px solid #5cdbff;
+ padding: 10px 25px;
+ font-size: 12pt;
+ font-weight: 600;
+ background-color: transparent;
+ text-shadow: #5cdbff 0 0 50px;
+}
+
+.icon {
+ font-family: 'Material Symbols Outlined'
+}
+
+h1 {
+ font-size: 40px;
+}