127 Commits

Author SHA1 Message Date
look-its-ashton
e77fe1406c Sprint 2 typo 2022-11-27 17:14:33 -08:00
look-its-ashton
57be3a11ed Merge branch 'sprint-2' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2 2022-11-27 17:07:34 -08:00
look-its-ashton
c381bd1f60 retrospectiev 2 started and sprint 2 review 2.md 2022-11-27 17:07:10 -08:00
Arthur Lu
83a0358869 fix form tag wrap issue
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-22 14:46:01 -08:00
Arthur Lu
5ba0dab1a1 fix flex-flow css linting issue
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 18:00:58 -08:00
Arthur Lu
1dfd8c91a2 fix css linting issues
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 17:55:44 -08:00
Arthur Lu
ecff5313a1 increase timeout for e2e tests
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 17:38:34 -08:00
Arthur Lu
a12de4e058 fix some more css issues
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 17:31:12 -08:00
Arthur Lu
9194dd5166 fix html linting and some css linting issues
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 17:27:18 -08:00
Arthur Lu
63a7d5ce1f Merge pull request #84 from cse110-fa22-group29/sprint-2-css-review-details
Sprint 2 css review details
2022-11-21 17:20:36 -08:00
Arthur Lu
9f9ac19b71 fix ReviewDetails CreatePage large tag display issue
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 17:20:12 -08:00
rheabhutada02
0912ea7956 fixed logo and tags
Co-authored-by: Kara Hoagland <KH-Cl@users.noreply.github.com>
Co-authored-by: Arthur Lu <learthurgo@gmail.com>
Co-authored-by: d7hernan <d7hernan@users.noreply.github.com>
2022-11-21 17:03:10 -08:00
rheabhutada02
b5e5a88163 fixed the pathing issue for images in main.e2e.test.js 2022-11-21 16:14:09 -08:00
rheabhutada02
5f1a246e6a moved all the icons to images and fixed path issues associated with this move 2022-11-21 16:12:17 -08:00
rheabhutada02
4073d2cc4b fixed and styled review details page
Co-authored-by: Kara Hoagland <KH-Cl@users.noreply.github.com>
Co-authored-by: Arthur Lu <learthurgo@gmail.com>
Co-authored-by: d7hernan <d7hernan@users.noreply.github.com>
2022-11-21 16:07:20 -08:00
rheabhutada02
23657853e5 Merge branch 'sprint-2-css-review-details' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2-css-review-details 2022-11-21 15:28:23 -08:00
rheabhutada02
ec9d0246ca fixed the update form, and update functionality, and formatted
Co-authored-by: Kara Hoagland <KH-Cl@users.noreply.github.com>
Co-authored-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 15:27:45 -08:00
Arthur Lu
1cbefee26f fix favicon linking
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 14:37:37 -08:00
Arthur Lu
dd56207892 fix update form listener
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 14:26:54 -08:00
rheabhutada02
123057f0f1 fixed the css linking 2022-11-21 13:56:00 -08:00
rheabhutada02
50283be4f5 renamed the file 2022-11-21 13:52:48 -08:00
rheabhutada02
46b1ec4b07 fixed form formatting, moved it to its own file 2022-11-21 13:52:44 -08:00
rheabhutada02
661feafa40 Merge branch 'sprint-2-css-review-details' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2-css-review-details
Co-authored-by: Arthur Lu <learthurgo@gmail.com>
Co-authored-by: Kara Hoagland <KH-Cl@users.noreply.github.com>
2022-11-21 12:35:52 -08:00
rheabhutada02
68b0c8edf5 cleaned css and html
Co-authored-by: Arthur Lu <learthurgo@gmail.com>
2022-11-21 12:32:54 -08:00
Kara Hoagland
5d2c446551 Merge pull request #83 from cse110-fa22-group29/remove-alt-img
remove alt from js/html/tests
2022-11-21 12:32:50 -08:00
Kara Hoagland
52bc6a27a4 default img if img fails to load 2022-11-21 12:29:06 -08:00
Kara Hoagland
1db54e9f7a remove alt from js/html/tests 2022-11-21 11:58:26 -08:00
d7hernan
1798835807 modified css for CreatePage and color palette for homepage
Co-authored-by: rheabhutada02
Co-authored-by: Kara Hoagland
2022-11-21 00:56:54 -08:00
rheabhutada02
1055f7ef26 updating font 2022-11-20 23:50:54 -08:00
Kara Hoagland
5a05741e08 Merge pull request #80 from cse110-fa22-group29/req-stars-fix
Req stars fix
2022-11-20 23:37:45 -08:00
d7hernan
4c5132c2b2 Merge branch 'sprint-2' into sprint-2-css-review-details 2022-11-20 22:49:51 -08:00
d7hernan
49f85d5468 color palette changes 2022-11-20 22:35:02 -08:00
d7hernan
9ef3c59fee added restaurant, tag, and comments to reviewDetails
Co-authored-by: rheabhutada02
2022-11-20 22:22:31 -08:00
d7hernan
069aff88af centered search journal form 2022-11-20 21:58:44 -08:00
d7hernan
6d126f6085 Merge branch 'sprint-2-css-review-details' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2-css-review-details 2022-11-20 21:21:25 -08:00
d7hernan
948f638cd7 fixed indentation 2022-11-20 21:21:18 -08:00
Arthur Lu
b24b1110f6 configure htmlHint and stylelint to use tab indentation,
fix html and css linting issues
2022-11-21 03:50:54 +00:00
Arthur Lu
eed39f580f cleanup css in homepage.css and index.html 2022-11-21 03:17:32 +00:00
Arthur Lu
259018ca97 fix linting issue 2022-11-21 03:06:47 +00:00
Arthur Lu
142e6d93b6 set e2e test connection to 2 seconds 2022-11-21 02:53:50 +00:00
Arthur Lu
a5ac2dc940 fix review card spacing and centering in homepage
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 17:03:55 -08:00
Arthur Lu
331f8e731c add some padding to icons
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 16:54:15 -08:00
Arthur Lu
19bbabe9b4 Merge pull request #82 from cse110-fa22-group29/sprint-2-css-review-details
Implement css and js for ReviewDetails
2022-11-20 16:41:41 -08:00
Arthur Lu
4336157371 Merge branch 'sprint-2' into sprint-2-css-review-details 2022-11-20 16:41:35 -08:00
Arthur Lu
9e82dae202 add comment for homepage mobile logic
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 16:39:51 -08:00
Arthur Lu
ccbf060c8c Merge branch 'sprint-2' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2 2022-11-20 16:31:34 -08:00
Arthur Lu
1f832aadd2 fix homepage structal issues,
TODO: clean css

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 16:31:32 -08:00
d7hernan
6ce15a094e css and js for ReviewDetails
Co-authored-by: Kara Hoagland <KH-Cl@users.noreply.github.com>
Co-authored-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 16:27:27 -08:00
Graydogminer
8a1c210515 fix htmlhint to allow tabs for indent 2022-11-20 16:20:23 -08:00
look-its-ashton
c412282e04 Merge branch 'sprint-2' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2 2022-11-20 15:46:37 -08:00
look-its-ashton
8c2ad629d2 updated main page 2022-11-20 15:46:13 -08:00
Arthur Lu
7b7abad2e6 fix error in test syntax
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 15:33:31 -08:00
Arthur Lu
70c863c378 Merge branch 'add-multiple-testing' into sprint-2 2022-11-20 15:29:16 -08:00
Arthur Lu
12e818e079 fix js linting
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 15:23:22 -08:00
Kara Hoagland
250617776b more details 2022-11-20 14:47:26 -08:00
Arthur Lu
9c531771f2 Merge pull request #75 from cse110-fa22-group29/allow-for-user-uploaded-images
implementation of basic image local storage
2022-11-20 14:43:50 -08:00
Henry Feng
131553ddeb Merge remote-tracking branch 'origin/sprint-2' into allow-for-user-uploaded-images 2022-11-20 14:40:17 -08:00
Arthur Lu
c5cc7bf309 update github actions with new npm script naming
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 14:36:13 -08:00
Kara Hoagland
302af4bbd5 tempIfElseAlert 2022-11-20 14:36:03 -08:00
Henry Feng
3c7b5f7f4e addresses case where image is not updated 2022-11-20 14:27:24 -08:00
Marc
3a7ed2fb16 fix stylelint to allow tabs as indent 2022-11-20 14:26:48 -08:00
Arthur Lu
dd3e0cfefb Merge branch 'sprint-2' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2 2022-11-20 14:17:12 -08:00
Arthur Lu
d284f0ddf2 change some npm scripts
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 14:17:10 -08:00
rheabhutada02
3db5f62a5c Merge branch 'sprint-2' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2 2022-11-20 14:12:37 -08:00
rheabhutada02
4f2d88db9f Co-authored-by: Gavyn Ezell <ezellgavyn@gmail.com>
Co-authored-by: Kara Hoagland <KH-Cl@users.noreply.github.com>
2022-11-20 14:12:34 -08:00
Arthur Lu
c3944d476b fix lintHTML and lintCSS commands
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 14:12:26 -08:00
Arthur Lu
8a9a32414e Merge branch 'sprint-2' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into sprint-2 2022-11-20 14:07:02 -08:00
Arthur Lu
e73a544ab2 fix js linting
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 14:07:01 -08:00
rheabhutada02
ce6b8fcfa6 Merge pull request #78 from cse110-fa22-group29/sprint-2-homepage-integration
Sprint 2 homepage integration
2022-11-20 14:06:32 -08:00
rheabhutada02
db3e8dba8d Merge branch 'sprint-2' into sprint-2-homepage-integration 2022-11-20 14:06:14 -08:00
Marc
f2edc4dc6a added for loops for multiple tests 2022-11-20 14:01:48 -08:00
Marc
5d331c3800 added for loops to tests 2022-11-20 13:56:27 -08:00
Henry Feng
f340f3ed82 Added local img storage to updating 2022-11-20 13:51:28 -08:00
rheabhutada02
2a6dbc0503 Merge pull request #76 from cse110-fa22-group29/sprint-2-homepage-integration
Sprint 2 homepage integration
2022-11-20 13:48:29 -08:00
Arthur Lu
72e2f0fa03 comment appTestHelpers.js
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 13:43:42 -08:00
Arthur Lu
3b1b0cfd57 quick async fix
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 13:39:52 -08:00
Arthur Lu
e7d8eaea59 fix issue with tag checking,
modularize frequent app opperations in appTestHelpers.js,
fix isue with tage count checking

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-20 13:39:21 -08:00
look-its-ashton
85d583e1b8 updating sprint2meeting3 2022-11-20 13:37:25 -08:00
look-its-ashton
bec66f1385 Sprint 2 Meeting 3 Meeting Notes 2022-11-20 13:18:00 -08:00
Arthur Lu
1c1ac64c58 change e2e tests to use default images
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-19 12:34:29 -08:00
Gavyn Ezell
5668e68594 first style integration
Co-authored-by: d7hernan <d7hernan@users.noreply.github.com>
Co-authored-by: look-its-ashton <look-its-ashton@users.noreply.github.com>
2022-11-19 12:29:50 -08:00
Arthur Lu
8338156cb8 fix delete test issue with alert handling
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-19 12:16:03 -08:00
Henry Feng
3e909ed381 Merge remote-tracking branch 'origin/sprint-2' into allow-for-user-uploaded-images 2022-11-19 12:10:55 -08:00
Arthur Lu
20e9842aea fix expected values for ratings and src tests
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-19 12:00:59 -08:00
Arthur Lu
7035fa46ee fixes to tag-add-btn,
fixes to tests with rating selection

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-19 11:42:30 -08:00
Gavyn Ezell
23ae101f56 testing images
Co-authored-by: d7hernan <d7hernan@users.noreply.github.com>
2022-11-19 11:19:57 -08:00
rheabhutada02
1379c22f6f Merge pull request #73 from cse110-fa22-group29/add-crud-e2e-testing
Add crud e2e testing
2022-11-19 10:58:14 -08:00
rheabhutada02
78c07f27d3 Merge pull request #66 from cse110-fa22-group29/storage-revamp
Storage revamp
2022-11-19 10:51:59 -08:00
rheabhutada02
c5229c7bc1 Updated ReviewDetails.js 2022-11-19 10:45:28 -08:00
Arthur Lu
20afab9b1f remove create test review card reference
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-19 10:21:43 -08:00
Arthur Lu
2e95147336 Merge branch 'add-crud-e2e-testing' of https://github.com/cse110-fa22-group29/cse110-fa22-group29 into add-crud-e2e-testing 2022-11-18 23:26:54 -08:00
Arthur Lu
ef5dccfd1a temp fix issue with root user 2022-11-18 23:26:51 -08:00
Marc
d5be6a2e4d Check details & homepage for create & read 2022-11-18 23:08:54 -08:00
Arthur Lu
274a05fdc2 convert page.click() to button.click() 2022-11-18 20:43:55 -08:00
Arthur Lu
65815998e9 fix create new review star selection 2022-11-18 20:37:33 -08:00
Arthur Lu
cac2b0bf07 populate part of add review,
various bug fixes,
TODO: resolve issue with star selectors
2022-11-18 20:36:10 -08:00
Arthur Lu
82be561bfe add wait for page navigation to applicable tests 2022-11-18 19:21:53 -08:00
Arthur Lu
b75e4172b4 Merge pull request #72 from cse110-fa22-group29/storage-revamp
Pull CRUD implementation changes from revamp-storage to add-crud-e2e-testing
2022-11-18 19:12:22 -08:00
Arthur Lu
32323eaf83 Merge pull request #71 from cse110-fa22-group29/sprint-2
Reflect changes to sprint-2 to storage-revamp
2022-11-18 15:28:38 -08:00
Arthur Lu
f332b27168 Merge pull request #70 from cse110-fa22-group29/remove-unused-files
Reflect main changes to sprint-2
2022-11-18 15:17:43 -08:00
Arthur Lu
0a39039e9c Merge pull request #69 from cse110-fa22-group29/remove-unused-files
Remove unused files
2022-11-18 15:16:40 -08:00
Arthur Lu
baa722b55e remove unused files
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-18 15:15:20 -08:00
Arthur Lu
9cf7baf3e5 remove commented form from index
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-18 14:43:59 -08:00
Arthur Lu
f6a9fb7fc5 remove implied init from localStorage unit tests
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-18 14:08:19 -08:00
Arthur Lu
a91c9bc7ef Merge pull request #68 from cse110-fa22-group29/add-app-to-readme
Add link to app in README.md
2022-11-18 13:51:28 -08:00
Arthur Lu
5f84e700d1 update e2e test layout 2022-11-18 12:34:59 -08:00
Arthur Lu
46cee253f3 Merge branch 'main' into add-app-to-readme 2022-11-18 01:33:51 -08:00
Arthur Lu
ca89953d41 add link to app in README.md 2022-11-18 09:31:53 +00:00
Arthur Lu
425bc45453 fix unit test action stall issue 2022-11-18 09:23:54 +00:00
Arthur Lu
3422f584f9 fix linting in js 2022-11-18 07:56:07 +00:00
Arthur Lu
89b7319dd8 cleanup unused html and js code 2022-11-18 07:52:43 +00:00
Arthur Lu
5e83338668 update unit tests to match new localStorage implementations 2022-11-18 07:51:08 +00:00
Arthur Lu
6493fbd171 modularize localStorage calls into localStorage.js in preparation for unit testing 2022-11-18 07:13:53 +00:00
Henry Feng
416d26658d implementation of basic image local storage 2022-11-17 16:17:51 -08:00
Arthur Lu
6c00246e2d fix linting issues
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-17 15:33:12 -08:00
Arthur Lu
c45aec116b fix e2e test for create,
split create test into two parts,
split other test templates into two parts

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-17 15:32:37 -08:00
Arthur Lu
1518fda766 add e2e tests for update and delete,
fix package.json commadns for lint and fix-style

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-17 13:54:58 -08:00
look-its-ashton
e4755dd074 sprint 2 meeting one rough draft 2022-11-17 13:24:59 -08:00
Arthur Lu
c66f43f6e9 add empty crud e2e tests
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
2022-11-17 12:32:38 -08:00
look-its-ashton
02f493e33b sprint 2 meeting one rough draft 2022-11-17 11:53:51 -08:00
rheabhutada02
ad723543e8 Merge pull request #58 from cse110-fa22-group29/updated-documentation
Added ADR for HTMLhint and Stylelint
2022-11-16 17:14:30 -08:00
rheabhutada02
56dceb5edb Rename checkin6.md to 111622-checkin6.md 2022-11-16 15:55:18 -08:00
rheabhutada02
41905a219b updated checkin6.md 2022-11-16 15:54:50 -08:00
rheabhutada02
467828d388 Rename 11822-sprint1day2.md to 110822-sprint1day2.md 2022-11-16 15:48:10 -08:00
Graydogminer
81ada40ca3 Create 111422-csslinting-stylelint.md 2022-11-14 01:05:58 -08:00
Graydogminer
cc6df228ed Create 111422-htmllinting-htmlhint.md 2022-11-14 00:48:27 -08:00
Graydogminer
1d453bdd49 Update phase1.md 2022-11-13 14:45:42 -08:00
59 changed files with 1685 additions and 999 deletions

View File

@@ -20,4 +20,4 @@ jobs:
- name: Install dependencies
run: sudo npm install
- name: Run tests
run: sudo npm run lintCSS
run: sudo npm run lint-css

View File

@@ -20,4 +20,4 @@ jobs:
- name: Install dependencies
run: sudo npm install
- name: Run tests
run: sudo npm run lintHTML
run: sudo npm run lint-html

View File

@@ -22,4 +22,4 @@ jobs:
- name: Install dependencies
run: sudo npm install
- name: Run tests
run: sudo npm run lint
run: sudo npm run lint-js

View File

@@ -24,6 +24,6 @@ jobs:
- name: Install dependencies
run: sudo npm install
- name: Start local http server
run: sudo npm run http-server
run: sudo npm run http-server &
- name: Run tests
run: sudo npm test

View File

@@ -1,3 +1,4 @@
{
"attr-value-not-empty": false
"attr-value-not-empty": false,
"space-tab-mixed-disabled": "tab"
}

View File

@@ -1,3 +1,7 @@
{
"extends": "stylelint-config-standard"
"extends": "stylelint-config-standard",
"ignore": ["inside-parens", "param", "value"],
"rules":{
"indentation": "tab"
}
}

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

View File

@@ -1,2 +1,5 @@
# cse110-fa22-group29
[Team Page Link](https://github.com/cse110-fa22-group29/cse110-fa22-group29/blob/main/admin/team.md)
[Food Journal](https://cse110-fa22-group29.github.io/cse110-fa22-group29/)

View File

@@ -31,6 +31,9 @@ So far the features listed below have been completed to some degree:
- Linting (JS)
- Implemented: ction triggers on any PR, uses eslint to perform style enforcement on all JS components
- ToDo: trigger workflow only on certain PRs which relate to JS code
- Linting (HTML)
- Implemented: action triggers on any PR, uses HTMLhint to perform style enforcement on all HTML components
- Linting (CSS)
- Implemented: action triggers on any PR, uses Stylelint to perform style enforcement on all CSS components
## Planned Features and Timeline

View File

@@ -0,0 +1,33 @@
# Meeting Minutes (11/16/2022)
## Team 29: Hackers1995
## Meeting Topic: Weekly TA Catchup with Gagan
We are meeting with Gagan to discuss Checkpoint 1 and Sprint 2 resolutions.
## Attendance
1. Rhea Bhutada
2. George Dubinin
3. Gagan Gopalaiah
4. Kara Hoagland
## Meeting Details
- When: 11/16/2022 at 3:30PM
- Where: Zoom
## Agenda:
## Discussion Points by Gagan
- Updated Gagan on Sprint 1
- looked at Girhub actions
- looked at the published page so far
- discussed retrospective
- Upcoming Assignments
- we have to come up with a video on the status of our app
- ramp up the styling part, so u can brag about the design of the app
- this video is supposed to encourage healthy competition
- Other Concerns
- JSDocs - not primary concern right now
- GitHub Pages vs. Netlify
- Gagan sees Netlify as more professional and not to difficult to implement
## End Time
- 11/09/2022 at 3:45PM

View File

@@ -0,0 +1,47 @@
# Meeting Minutes (11/07/2022)
## Team 29: Hackers1995
## Meeting Topic: First Sprint
Meeting notes for the first sprint
## Attendance
1. Rhea Bhutada
2. George Dubinin
3. Gavyn Ezell
4. Henry Feng
5. Kara Hoagland
6. Marc Reta
7. Sanjit Joseph
8. Daniel Hernandez
9. Arthur Lu
10. Isaac Otero
## Meeting Details
- When: 11/17/2022 at 11:30PM
- Where: Design & Innovation Building
## Agenda:
- ### Old/Unresolved Business
- N/A
- ### New Business
- Second sprint commences!
- Focus on design progress for the project showoff
- Cuisine vs Tag identifiers for reviews (both?)
- localStorage will hold:
- list of active IDs which is updated for very create operation. An ID uniquely identifies a review
- value, "nextId" denoting the index of the next available slot for an Id
- entries for every single review (javascript object)
- a list for every tag that denotes which Ids belong to reviews containing this tag
End2end tests will rely on specific html element names which include the following:
- "create-btn" (located on homepage and used to create a new review)
- "submit-btn" (located on form and used to post review)
- "update-btn" (located on a specific review page)
- "delete-btn" (located on a specific review page)
- "tag-add-btn" (located on the review create form)
- ### Next Meeting's Business
## Decisions Made
-
## End Time
- 11/17/2022 at 1:00PM

View File

@@ -0,0 +1,36 @@
# Meeting Minutes (11/20/2022)
## Team 29: Hackers1995
## Meeting Topic: Second Sprint Meeting 3
<what are we working on today>
## Attendance
1. Rhea Bhutada
2. George Dubinin
3. Gavyn Ezell
4. Henry Feng
5. Kara Hoagland
6. Marc Reta
7. Sanjit Joseph
8. Daniel Hernandez
9. Arthur Lu
10. Isaac Otero
## Meeting Details
- When: 11/20/2022 at 1:00PM
- Where: CSE Building Second Floor
## Agenda:
- ### Old/Unresolved Business
- N/A
- ### New Business
- Planning for the Agile Steam Status Video
- *Present the status of your software*
- *Description of current challenges to development*
- *Preview of the next sprint and what to look forward to*
- ### Next Meeting's Business
## Decisions Made
-
## End Time
- 11/20/2022 at 3:00PM

View File

View File

@@ -0,0 +1,60 @@
# Sprint 2 Review Meeting Minutes (11/27/2022)
## Team 29: Hackers1995
## Meeting Topic: Sprint 2 Review
We are reviewing the second sprint 2 progress made and highlights
## Attendance
1. Rhea Bhutada
2. George Dubinin
3. Sanjit Joseph
4. Kara Hoagland
5. Arthur Lu
6. Mark Rheta
7. Henry Feng
8. Gavyn Etzel
9. Sanjit Joseph
10. Isaac Otero
## Meeting Details
- When: 11/27/2022 at 4:30PM
- Where: Zoom
## Agenda:
Review the second sprint and discuss assiget the writeup for the Agile review assignemnt
## Sprint 2 REVIEW
In collecting feedback for the sprint the leads decided to ask members individually about their experience during sprint 2 to then summarize these responses. Each member was asked 4 questions with their summarized responses below:
### ➼ What do you think worked well in the first sprint?
Communication within the group was improved and our joint study sessions where more productive. The design team got the support they needed to accomplish the majority of their work on the project. The push to emphasize the sub-teams responsible for different tasks turned out to be a great idea and everyone put in a good effort.
### ➼ What can we improve on for the next sprint?
With the vast majority of feature implementation underway the rapid progress created a lot of bugs which otherwise could have been avoid with more careful planning. Some members felt that even though they made a great effort they weren't able to contribute as much as they wanted to. Some of the code documentation fell behind and some design discussions were circumvented because some members where busy. One consequence was that relatively few ADRs were created even though we made many important design decisions during sprint 2.
### ➼ What was your contribution to the sprint?
* Rhea Bhutada: I mainly helped implement the backend for the CRUD features of the app and documentation related to this. This mainly entailed changing the way that we were storing user data in local storage. Additionally, I helped design the form and homepage.
* Gavyn Etzel:
* Henry Feng: Worked on implementing local image uploading and storing features for updating and creating profiles.
* Sanjit: I reimplemented the star ratings since they had some issues and werent merged with sprint 1. I fixed a bunch of linting issues that popped up from that as well. I did a fair bit of color palette brainstorming with the team. I also went over our app design for the sprint video and edited that together. Most importantly I put a chef hat on the raccoon
* Daniel:
* Arthur Lu: Worked on fixing some CI/CD pipeline issues
Implemented e2e testing for basic update and delete functionality
Helped with fixing the homepage and review page layout
Helped with fixing the article tag overflow issue
* Marc Rheta: Implemented the e2e testing for reading and create
Allowed tabs for CSS/HTML linters
* Isaac Otero: I was able to help out with the sprint video for the last sprint and thought of how our page will look like, Started working on homepage.html
* George Dubinin: Meeting notes, Repo organization, Front-end (a little), Project Status Review video.
* Kara Hoagland: I helped set up the new local storage design, reimplemented the CRUD features using the new local storage design, contributed to the styling, added a default img, backend on the details page
### ➼ Was there anything blocking your progress in the sprint?
A few members got sick over the break and with midterms picking up for other classes some members had trouble dedicting time for the project but everyone still put in a great effort overall.
## Next Sprint Goals
- Resolve the 4 issues open on GitHub right now
- Make the project "local first" by creating a cache
- Bug fixes and final product adjustments possibly pushed to sprint 4
- We aim to keep sprint 3 short (a few days max)
- JS docs (we can potentially leave this out with an explanation of where our documentation is)
## End Time
- 11/27/2022 at 5:00PM

View File

@@ -4,20 +4,21 @@
"type": "module",
"scripts": {
"test": "mocha --recursive --require mock-local-storage './{,!(node_modules)/**}/*.test.js'",
"lint": "eslint '**/*.js'",
"fix-style": "eslint --fix **/*.js",
"lintHTML": "htmlhint '**/*.html'",
"lintCSS": "stylelint '**/*.css'",
"lint-js": "eslint **/*.js",
"fix-js": "eslint --fix **/*.js",
"lint-html": "htmlhint **/*.html",
"lint-css": "stylelint **/*.css",
"fix-css": "stylelint --fix **/*.css",
"http-server": "http-server source"
},
"devDependencies": {
"eslint": "^8.27.0",
"htmlhint": "1.1.4",
"http-server": "",
"mocha": "10",
"mock-local-storage": "^1.1.23",
"puppeteer": "^18.2.1",
"stylelint": "14.14.1",
"stylelint-config-standard": "^29.0.0",
"puppeteer": "18",
"http-server": ""
"stylelint-config-standard": "^29.0.0"
}
}

View File

@@ -7,6 +7,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Food Journal</title>
<!--Add Favicon-->
<link rel="icon" type="image/x-icon" href="./assets/images/favicon.ico">
<!-- Recipe Card Custom Element -->
<script src="assets/scripts/ReviewCard.js" type="module"></script>
@@ -14,64 +17,77 @@
<!-- Main Stylesheets & Scripts -->
<!-- Temporarily commented out reset.css due to furthur discussion needed on the values of the default config-->
<!-- <link rel="stylesheet" href="/static/reset.css" /> -->
<link rel="stylesheet" href="./static/ReviewCard.css" />
<link rel="stylesheet" href="./static/CreatePage.css" />
<link rel="stylesheet" href="./static/Form.css" />
<script src="./assets/scripts/CreatePage.js" type="module"></script>
</head>
<body>
<input type="button" value="Home" id="home-btn" onclick="window.location.assign('./index.html')">
<form id="new-food-entry">
<fieldset>
<legend>Pic:</legend>
<label for="mealImage">
Source:
<input type="text" id="mealImg" name="mealImg">
</label>
<label for="image-alt">
Alt Text:
<input type="text" id="imgAlt" name="imgAlt">
</label>
</fieldset>
<fieldset>
<legend> Meal: </legend>
<label for="Meal: ">Meal:
<input type="text" id="mealName" name="mealName" required>
</label>
<label for="comments">Comments:
<br>
<textarea name="comments" id="comments"></textarea>
</label>
</fieldset>
<fieldset class="rating">
<legend> Rating: </legend>
<input type="radio" id="s5" name="rating" value="5"/> <label for="s5"> 5 stars </label>
<input type="radio" id="s4" name="rating" value="4"/> <label for="s4"> 4 stars </label>
<input type="radio" id="s3" name="rating" value="3"/> <label for="s3"> 3 stars </label>
<input type="radio" id="s2" name="rating" value="2"/> <label for="s2"> 2 stars </label>
<input type="radio" id="s1" name="rating" value="1"/> <label for="s1"> 1 star </label>
</fieldset>
<fieldset>
<legend>Other Info:</legend>
<label for="restaurant">
Restaurant:
<input type="text" id="restaurant" name="restaurant" required>
</label>
<label for="tag-form">
Tags:
<input type="text" id="tag-form" name="tag-form">
<div class='tag-container' id="tag-container-form">
<header>
<div class="top-bar">
<img src ="./assets/images/Logo.png" alt="logo" />
<h1> Food Journal </h1>
<img src ="./assets/images/Logo.png" alt="logo" />
</div>
<button type="button" id="tagAdd">Add Tag</button>
</label>
</header>
<body>
<div class="journal-form">
<h1>New Entry</h1>
<form id="new-food-entry">
<fieldset>
<legend>PICTURE:</legend>
<select id="select" name="select">
<option value="file">File Upload</option>
<option value="url">From an URL</option>
</select>
<label for="mealImage" id="source">
<input type="file" accept="image/*" id="mealImg" name="mealImg">
</label>
</fieldset>
<button type="submit" id="save-btn" value="Submit">Save Review</button>
<fieldset>
<legend>MEAL NAME:</legend>
<label for="Name: "> <input type="text" id="mealName" name="mealName" required> </label>
</fieldset>
<fieldset>
<legend>RESTAURANT NAME:</legend>
<label for="Name:"> <input type="text" id="restaurant" name="restaurant" required> </label>
</fieldset>
<fieldset>
<legend>RATING:</legend>
<div style="display: flex; justify-content: flex-start; align-items: center;">
<div class="rating">
<input type="radio" id="s5" name="rating" value="5"/> <label for="s5" id="s5-select"> 5 stars </label>
<input type="radio" id="s4" name="rating" value="4"/> <label for="s4" id="s4-select"> 4 stars </label>
<input type="radio" id="s3" name="rating" value="3"/> <label for="s3" id="s3-select"> 3 stars </label>
<input type="radio" id="s2" name="rating" value="2"/> <label for="s2" id="s2-select"> 2 stars </label>
<input type="radio" id="s1" name="rating" value="1"/> <label for="s1" id="s1-select"> 1 star </label>
</div>
</div>
</fieldset>
<fieldset>
<legend>COMMENTS:</legend>
<textarea name="comments" id="comments" rows="5" style="resize: none; width: 100%;"></textarea>
</fieldset>
<fieldset>
<legend>TAGS: (ex. cuisine, distance, cost, etc)</legend>
<input type="text" id="tag-form" name="tag-form">
<div class='tag-container' id="tag-container-form">
</div>
<button type="button" id="tag-add-btn"> + </button>
</fieldset>
<button type="submit" id="save-btn" value="Submit">Save</button>
<input type="button" value="Cancel" id="home-btn" onclick="window.location.assign('./index.html')">
</form>
</div>
</body>
</html>

View File

@@ -6,73 +6,117 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Food Journal</title>
<!--Add Favicon-->
<link rel="icon" type="image/x-icon" href="./assets/images/icons/favicon.ico">
<!-- Recipe Card Custom Element -->
<script src="assets/scripts/ReviewCard.js" type="module"></script>
<!-- Main Stylesheets & Scripts -->
<!-- Temporarily commented out reset.css due to furthur discussion needed on the values of the default config-->
<!-- <link rel="stylesheet" href="/static/reset.css" /> -->
<link rel="stylesheet" href="./static/ReviewCard.css" />
<link rel="stylesheet" href="./static/ReviewDetails.css" />
<link rel="stylesheet" href="./static/Form.css" />
<script src="assets/scripts/ReviewDetails.js" type="module"></script>
</head>
<body>
<main>
<input type="button" value="Home" id="home-btn" onclick="window.location.assign('./index.html')">
<button type="button" id="update-btn">Update</button>
<button type="button" id="delete-btn" class="danger">Delete</button>
</main>
<!----> <form id="update-food-entry" class="hidden">
<fieldset>
<legend>Pic:</legend>
<label for="mealImage">
Source:
<input type="text" id="mealImg" name="mealImg">
</label>
<label for="image-alt">
Alt Text:
<input type="text" id="imgAlt" name="imgAlt">
</label>
</fieldset>
<fieldset>
<legend> Meal: </legend>
<label for="Meal: ">Meal:
<input type="text" id="mealName" name="mealName" required>
</label>
<label for="comments">Comments:
<br>
<textarea name="comments" id="comments"></textarea>
</label>
</fieldset>
<fieldset class="rating">
<legend> Rating: </legend>
<input type="radio" id="s5" name="rating" value="5"/> <label for="s5"> 5 stars </label>
<input type="radio" id="s4" name="rating" value="4"/> <label for="s4"> 4 stars </label>
<input type="radio" id="s3" name="rating" value="3"/> <label for="s3"> 3 stars </label>
<input type="radio" id="s2" name="rating" value="2"/> <label for="s2"> 2 stars </label>
<input type="radio" id="s1" name="rating" value="1"/> <label for="s1"> 1 star </label>
</fieldset>
<fieldset>
<legend>Other Info:</legend>
<label for="restaurant">
Restaurant:
<input type="text" id="restaurant" name="restaurant" required>
</label>
<label for="tag-form">
Tags:
<input type="text" id="tag-form" name="tag-form">
<div class='tag-container' id="tag-container-form">
<header>
<div class="top-bar">
<img src ="./assets/images/Logo.png" alt="logo" />
<h1> Food Journal </h1>
<img src ="./assets/images/Logo.png" alt="logo" />
</div>
<button type="button" id="tag-add-btn">Add Tag</button>
</label>
</header>
<main>
<div class="journal-form" id="review-details">
<form>
<fieldset class = "meal-name">
<h1 id="d-mealName" style="font-family: Century Gothic;"></h1>
<h1 id="d-restaurant" style="font-family: Century Gothic; font-size: 30px;"></h1>
</fieldset>
<button type="submit" value="Submit">Add Review</button>
<fieldset class = "meal-pics">
<!-- image source -->
<img width=40% height=40% id="d-mealImg" style="margin-left: auto; margin-right: auto; display: block;"/>
</fieldset>
<fieldset class = "stars-and-comments" style="text-align: center;">
<img width=30% height=30% id="d-rating" style="margin-left: auto; margin-right: auto; display: block;"/>
<p id = "d-comments"></p>
</fieldset>
<fieldset class = "meal-tags">
<div class = "tag-container" id="d-tags" style="justify-content: center;"></div>
</fieldset>
</form>
</div>
<!---Navigation Buttons-->
<div style="display: flex; justify-content: center;">
<img src="./assets/images/home_button_for_interface.png" style="margin: 20px 10px 20px 10px;" id="home-btn" onclick="window.location.assign('./index.html')" height="50" width="50"/>
<img src ="./assets/images/edit_button_for_interface.png" style="margin: 20px 10px 20px 10px;" id="update-btn" height="50" width="50"/>
<img src ="./assets/images/delete_icon_for_interface.png" style="margin: 20px 10px 20px 10px;" id="delete-btn" class="danger" height="50" width="50"/>
</div>
</main>
<div class="journal-form hidden" id="update-form">
<h1>Update Entry</h1>
<form id="new-food-entry">
<fieldset>
<legend>PICTURE:</legend>
<select id="select" name="select">
<option value="file">File Upload</option>
<option value="url">From an URL</option>
</select>
<label for="mealImage" id="source">
<input type="file" accept="image/*" id="mealImg" name="mealImg">
</label>
</fieldset>
<fieldset>
<legend>MEAL NAME:</legend>
<label for="Name: "> <input type="text" id="mealName" name="mealName" required> </label>
</fieldset>
<fieldset>
<legend>RESTAURANT NAME:</legend>
<label for="Name:"> <input type="text" id="restaurant" name="restaurant" required> </label>
</fieldset>
<fieldset>
<legend>RATING:</legend>
<div style="display: flex; justify-content: flex-start; align-items: center;">
<div class="rating">
<input type="radio" id="s5" name="rating" value="5"/> <label for="s5" id="s5-select"> 5 stars </label>
<input type="radio" id="s4" name="rating" value="4"/> <label for="s4" id="s4-select"> 4 stars </label>
<input type="radio" id="s3" name="rating" value="3"/> <label for="s3" id="s3-select"> 3 stars </label>
<input type="radio" id="s2" name="rating" value="2"/> <label for="s2" id="s2-select"> 2 stars </label>
<input type="radio" id="s1" name="rating" value="1"/> <label for="s1" id="s1-select"> 1 star </label>
</div>
</div>
</fieldset>
<fieldset>
<legend>COMMENTS:</legend>
<textarea name="comments" id="comments" rows="5" style="resize: none; width: 100%;"></textarea>
</fieldset>
<fieldset>
<legend>TAGS: (ex. cuisine, distance, cost, etc)</legend>
<input type="text" id="tag-form" name="tag-form">
<div class='tag-container' id="tag-container-form">
</div>
<button type="button" id="tag-add-btn"> + </button>
</fieldset>
<button type="submit" id="save-btn" value="Submit">Save</button>
<input type="button" value="Cancel" id="home-btn" onclick="window.location.assign('./index.html')">
</form>
</div>
</body>
</html>

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 311 KiB

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

View File

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -1,3 +1,5 @@
import { newReviewToStorage } from "./localStorage.js";
window.addEventListener("DOMContentLoaded", init);
function init() {
@@ -14,6 +16,43 @@ function initFormHandler() {
let tagContainer = document.getElementById("tag-container-form");
let form = document.querySelector("form");
/*
* change the input source of the image between local file and URL
* depending on user's selection
*/
let select = document.getElementById("select");
select.addEventListener("change", function() {
const input = document.getElementById("source");
if (select.value == "file") {
input.innerHTML = `
Source:
<input type="file" accept="image/*" id="mealImg" name="mealImg">
`;
}
//TODO: change to photo taking for sprint 3
else {
input.innerHTML = `
Source:
<input type="text" id="mealImg" name="mealImg">
`;
}
});
//addressing sourcing image from local file
let imgDataURL = "";
document.getElementById("mealImg").addEventListener("change", function() {
const reader = new FileReader();
//store image data URL after successful image load
reader.addEventListener("load", ()=>{
imgDataURL = reader.result;
}, false);
//convert image file into data URL for local storage
reader.readAsDataURL(document.getElementById("mealImg").files[0]);
});
form.addEventListener("submit", function(e){
/*
* User submits the form for their review.
@@ -28,7 +67,11 @@ function initFormHandler() {
if (`${key}` !== "tag-form") {
reviewObject[`${key}`] = `${value}`;
}
if (`${key}` === "mealImg" && select.value == "file") {
reviewObject["mealImg"] = imgDataURL;
}
}
if(reviewObject["rating"] != null){
reviewObject["tags"] = [];
let tags = document.querySelectorAll(".tag");
@@ -37,28 +80,17 @@ function initFormHandler() {
tagContainer.removeChild(tags[i]);
}
//grabbing the nextID, and putting our review object in storage associated with the ID
let nextReviewId = JSON.parse(localStorage.getItem("nextID"));
reviewObject["reviewID"] = nextReviewId;
localStorage.setItem("review"+nextReviewId, JSON.stringify(reviewObject));
let nextReviewId = newReviewToStorage(reviewObject);
sessionStorage.setItem("currID", JSON.stringify(nextReviewId));
//updating our activeIDS list
let tempIdArr = JSON.parse(localStorage.getItem("activeIDS"));
tempIdArr.push(nextReviewId);
localStorage.setItem("activeIDS", JSON.stringify(tempIdArr));
//increment nextID for next review creation
nextReviewId++;
localStorage.setItem("nextID", JSON.stringify(nextReviewId));
window.location.assign('./ReviewDetails.html');
window.location.assign("./ReviewDetails.html");
} else{
window.alert("NO! FILL IN STARS");
}
});
let tagAddBtn = document.getElementById("tagAdd");
let tagAddBtn = document.getElementById("tag-add-btn");
tagAddBtn.addEventListener("click", ()=> {
let tagField = document.getElementById("tag-form");
if (tagField.value.length > 0) {

View File

@@ -13,9 +13,10 @@ class ReviewCard extends HTMLElement {
let styleEl = document.createElement("style");
styleEl.textContent = `
* {
font-family: sans-serif;
font-family: Century Gothic;
margin: 0;
padding: 0;
overflow-wrap: anywhere;
}
a {
@@ -28,7 +29,7 @@ class ReviewCard extends HTMLElement {
article {
align-items: center;
border: 1px solid rgb(223, 225, 229);
border: 2px solid rgb(31, 41, 32);
border-radius: 8px;
display: grid;
grid-template-rows: 118px 56px 14px 18px 15px 36px;
@@ -36,6 +37,7 @@ class ReviewCard extends HTMLElement {
row-gap: 5px;
padding: 0 16px 16px 16px;
width: 178px;
margin: 8px 8px 8px 8px;
}
div.rating {
@@ -52,9 +54,9 @@ class ReviewCard extends HTMLElement {
}
article>img {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
height: 118px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
height: 119px;
object-fit: cover;
margin-left: -16px;
width: calc(100% + 32px);
@@ -80,6 +82,22 @@ class ReviewCard extends HTMLElement {
color: #70757A;
font-size: 12px;
}
.tag-container {
margin-top: 20px;
display: flex;
flex-flow: row wrap;
}
.a-tag {
background-color:#94da97;
border-radius: 7px;
color: #94da97;
padding-right: 7px;
padding-left: 7px;
margin: 3px;
font-weight: bold;
}
`;
articleEl.append(styleEl);
shadowEl.append(articleEl);
@@ -116,7 +134,6 @@ class ReviewCard extends HTMLElement {
* following format:
* {
* "mealImg": "string",
* "imgAlt": "string",
* "mealName": "string",
* "comments": "string",
* "rating": number,
@@ -137,13 +154,12 @@ class ReviewCard extends HTMLElement {
//image setup
let mealImg = document.createElement("img");
mealImg.setAttribute("id", "a-mealImg");
mealImg.setAttribute("alt",data["imgAlt"]);
if(data["mealImg"] != ""){
mealImg.setAttribute("alt","Meal Photo Corrupted");
mealImg.setAttribute("src",data["mealImg"]);
}
else{
mealImg.setAttribute("src", "./assets/images/icons/plate_with_cutlery.png");
}
mealImg.addEventListener("error", function(e) {
mealImg.setAttribute("src", "./assets/images/plate_with_cutlery.png");
e.onerror = null;
});
//meal name setup
let mealLabel = document.createElement("label");
@@ -168,7 +184,7 @@ class ReviewCard extends HTMLElement {
ratingDiv.setAttribute("class", "rating");
let starsImg = document.createElement("img");
starsImg.setAttribute("id", "a-rating");
starsImg.setAttribute("src", "./assets/images/icons/"+data["rating"]+"-star.svg");
starsImg.setAttribute("src", "./assets/images/"+data["rating"]+"-star.svg");
starsImg.setAttribute("alt", data["rating"] +" stars");
starsImg.setAttribute("num", data["rating"]);
ratingDiv.append(starsImg);
@@ -181,7 +197,7 @@ class ReviewCard extends HTMLElement {
if(data["tags"]){
for (let i = 0; i < data["tags"].length; i++) {
let newTag = document.createElement("label");
newTag.setAttribute("class","tag");
newTag.setAttribute("class","a-tag");
newTag.innerHTML = data["tags"][i];
tagContainer.append(newTag);
}
@@ -210,7 +226,6 @@ class ReviewCard extends HTMLElement {
* following format:
* {
* "mealImg": "string",
* "imgAlt": "string",
* "mealName": "string",
* "comments": "string",
* "rating": number,
@@ -228,7 +243,6 @@ class ReviewCard extends HTMLElement {
//get image
let mealImg = this.shadowEl.getElementById("a-mealImg");
dataContainer["mealImg"] = mealImg.getAttribute("src");
dataContainer["imgAlt"] = mealImg.getAttribute("alt");
//get meal name
let mealLabel = this.shadowEl.getElementById("a-mealName");

View File

@@ -1,30 +1,64 @@
//reviewDetails.js
import {getReviewsFromStorage, saveReviewsToStorage} from "./localStorage.js";
import {deleteReviewFromStorage, getReviewFromStorage, updateReviewToStorage} from "./localStorage.js";
// Run the init() function when the page has loaded
window.addEventListener("DOMContentLoaded", init);
function init(){
setupInfo();
setupDelete();
setupUpdate();
}
function setupInfo(){
let currID = JSON.parse(sessionStorage.getItem("currID"));
let currReview = getReviewFromStorage(currID);
//meal image
let mealImg = document.getElementById("d-mealImg");
mealImg.setAttribute("src",currReview["mealImg"]);
mealImg.addEventListener("error", function(e) {
mealImg.setAttribute("src", "./assets/images/plate_with_cutlery.png");
e.onerror = null;
});
//meal name
let mealLabel = document.getElementById("d-mealName");
mealLabel.innerHTML = currReview["mealName"];
//restaurant name
let restaurantLabel = document.getElementById("d-restaurant");
restaurantLabel.innerHTML = currReview["restaurant"];
//comments
let comments = document.getElementById("d-comments");
comments.innerText = currReview["comments"];
//rating
let starsImg = document.getElementById("d-rating");
starsImg.setAttribute("src", "./assets/images/"+currReview["rating"]+"-star.svg");
starsImg.setAttribute("alt", currReview["rating"] +" stars");
//tags
let tagContainer = document.getElementById("d-tags");
if(currReview["tags"]){
for (let i = 0; i < currReview["tags"].length; i++) {
let newTag = document.createElement("label");
newTag.setAttribute("class","d-tag");
newTag.innerHTML = currReview["tags"][i];
tagContainer.append(newTag);
}
}
}
function setupDelete(){
let deleteBtn = document.getElementById("delete-btn");
let currID = JSON.parse(sessionStorage.getItem("currID"));
let activeIDS = JSON.parse(localStorage.getItem("activeIDS"));
deleteBtn.addEventListener("click", function(){
if(window.confirm("Are you sure you want to delete this entry?")){
for (let i in activeIDS) {
if (activeIDS[i] == currID) {
activeIDS.splice(i,1);
localStorage.setItem('activeIDS', JSON.stringify(activeIDS));
sessionStorage.removeItem('currID');
localStorage.removeItem(`review${currID}`);
deleteReviewFromStorage(currID);
sessionStorage.removeItem("currID");
window.location.assign("./index.html");
break;
}
}
}
});
}
@@ -32,17 +66,18 @@ function setupDelete(){
function setupUpdate(){
let updateBtn = document.getElementById("update-btn");
let currID = JSON.parse(sessionStorage.getItem("currID"));
let currReview = JSON.parse(localStorage.getItem(`review${currID}`));
let form = document.getElementById("update-food-entry");
let currReview = getReviewFromStorage(currID);
let form = document.getElementById("new-food-entry");
let updateDiv = document.getElementById("update-form");
updateBtn.addEventListener("click", function(){
//update function
if(currReview){
form.style.display = "block";
updateDiv.classList.remove("hidden");
let tagContainer = document.getElementById("tag-container-form");
//Set value of each input element to current's values
document.getElementById("mealImg").defaultValue = currReview["mealImg"];
document.getElementById("imgAlt").defaultValue = currReview["imgAlt"];
document.getElementById("mealName").defaultValue = currReview["mealName"];
document.getElementById("comments").textContent = currReview["comments"];
document.getElementById("s" + `${currReview["rating"]}`).checked = true;
@@ -62,6 +97,46 @@ function setupUpdate(){
tagContainer.append(newTag);
}
}
/*
* change the input source of the image between local file and URL
* depending on user's selection
*/
let select = document.getElementById("select");
select.addEventListener("change", function() {
const input = document.getElementById("source");
if (select.value == "file") {
input.innerHTML = `
Source:
<input type="file" accept="image/*" id="mealImg" name="mealImg">
`;
}
//TODO: change to photo taking for sprint 3
else {
input.innerHTML = `
Source:
<input type="text" id="mealImg" name="mealImg">
`;
}
});
//addressing sourcing image from local file
let imgDataURL = "";
document.getElementById("mealImg").addEventListener("change", function() {
console.log("reading used");
const reader = new FileReader();
//store image data URL after successful image load
reader.addEventListener("load", ()=>{
imgDataURL = reader.result;
}, false);
//convert image file into data URL for local storage
reader.readAsDataURL(document.getElementById("mealImg").files[0]);
});
//Take formdata values as newData when submit
form.addEventListener("submit", function(){
/*
@@ -76,6 +151,13 @@ function setupUpdate(){
if (`${key}` !== "tag-form") {
newData[`${key}`] = `${value}`;
}
//Account for the case where image is not updated
if (`${key}` === "mealImg" && document.getElementById("mealImg").value === "") {
newData["mealImg"] = currReview["mealImg"];
}
else if (`${key}` === "mealImg" && select.value == "file") {
newData["mealImg"] = imgDataURL;
}
}
newData["tags"] = [];
@@ -87,10 +169,9 @@ function setupUpdate(){
newData["reviewID"] = currID;
updateReviewToStorage(currID, newData);
localStorage.setItem("review"+currID, JSON.stringify(newData));
form.style.display = "none";
updateDiv.classList.add("hidden");
});
@@ -109,6 +190,5 @@ function setupUpdate(){
tagField.value = "";
}
});
}
});
}

View File

@@ -1,13 +0,0 @@
// Run the init() function when the page has loaded
window.addEventListener("DOMContentLoaded", init);
function init() {
let result = sessionStorage.getItem("currReview");
let main = document.querySelector("main");
main.innerHTML = result;
let p = document.createElement("p");
p.innerHTML = JSON.parse(result)["comments"];
main.append(p);
}

View File

@@ -0,0 +1,73 @@
import {strict as assert} from "node:assert";
/**
* Fills out a create or update review form
* @param {Object} page the page object which contains the create or update form
* @param {Object} review review data to input into the form
*/
export async function setReviewForm(page, review) {
// Set text fields
await page.$eval("#mealName", (el, value) => el.value = value, review.mealName);
await page.$eval("#comments", (el, value) => el.value = value, review.comments);
await page.$eval("#restaurant", (el, value) => el.value = value, review.restaurant);
// Get all tag elements and click them to delete them
let tag_items = await page.$$(".tag");
if(tag_items !== null){
for(let i = 0; i < tag_items.length; i++){
await tag_items[i].click();
}
}
// Get the button needed to add new tags
let tag_btn = await page.$("#tag-add-btn");
for(let i = 0; i < review.tags.length; i++){
await page.$eval("#tag-form", (el, value) => el.value = value, review.tags[i]);
await tag_btn.click();
}
// Select a new rating
let rating_select = await page.$(`#s${review.rating}-select`);
await rating_select.click({delay: 100});
}
/**
* Tests a page or shadowDOM for correct element text or src values
* @param {Object} root page or shodowDOM to test
* @param {string} prefix prefix character for element IDs
* @param {Object} expected values for each element
*/
export async function checkCorrectness(root, prefix, expected){
// Get the review image and check src
let img = await root.$(`#${prefix}-mealImg`);
let imgSrc = await img.getProperty("src");
// Check src
assert.strictEqual(await imgSrc.jsonValue(), expected.imgSrc);
// Get the title, comment, and restaurant
let title = await root.$(`#${prefix}-mealName`);
let title_text = await title.getProperty("innerText");
let comment = await root.$(`#${prefix}-comments`);
let comment_text = await comment.getProperty("innerText");
let restaurant = await root.$(`#${prefix}-restaurant`);
let restaurant_text = await restaurant.getProperty("innerText");
// Check title, comment, and restaurant
assert.strictEqual(await title_text.jsonValue(), expected.mealName);
assert.strictEqual(await comment_text.jsonValue(), expected.comments);
assert.strictEqual(await restaurant_text.jsonValue(), expected.restaurant);
// Check tags
let tags = await root.$$(`.${prefix}-tag`);
assert.strictEqual(await tags.length, expected.tags.length);
for(let i = 0; i < expected.tags.length; i++){
let tag_text = await tags[i].getProperty("innerText");
assert.strictEqual(await tag_text.jsonValue(), expected.tags[i]);
}
// Check stars
let stars = await root.$(`#${prefix}-rating`);
let stars_src = await stars.getProperty("src");
assert.strictEqual(await stars_src.jsonValue(), expected.rating);
}

View File

@@ -1,7 +1,67 @@
/**
* @returns {Array<Object>} An array of reviews found in localStorage
* Creates a new review to storage and performs related meta tasks
* @param {Object} review to store
* @return {number} ID of the newly added review
*/
export function getReviewsFromStorage() {
export function newReviewToStorage(review){
//grabbing the nextID, and putting our review object in storage associated with the ID
let nextReviewId = JSON.parse(localStorage.getItem("nextID"));
review["reviewID"] = nextReviewId;
// set the review entry to the review object
localStorage.setItem(`review${nextReviewId}`, JSON.stringify(review));
//updating our activeIDS list
let tempIdArr = JSON.parse(localStorage.getItem("activeIDS"));
tempIdArr.push(nextReviewId);
localStorage.setItem("activeIDS", JSON.stringify(tempIdArr));
//increment nextID for next review creation
localStorage.setItem("nextID", JSON.stringify(nextReviewId + 1));
return nextReviewId;
}
/**
* Gets a single review by ID from storage
* @param {string} ID of the review to get
* @returns {Object} review object corresponding to param ID
*/
export function getReviewFromStorage(ID){
return JSON.parse(localStorage.getItem(`review${ID}`));
}
/**
* Updates a single review by ID to storage
* @param {string} ID of review to update
* @param {Object} review to store
*/
export function updateReviewToStorage(ID, review){
// set the review entry with ID to the review object
localStorage.setItem(`review${ID}`, JSON.stringify(review));
}
/**
* Deletes a review by ID from storage
* @param {string} ID of the review to delete
*/
export function deleteReviewFromStorage(ID){
let activeIDS = JSON.parse(localStorage.getItem("activeIDS"));
for (let i in activeIDS) {
if (activeIDS[i] == ID) {
activeIDS.splice(i,1);
localStorage.setItem("activeIDS", JSON.stringify(activeIDS));
localStorage.removeItem(`review${ID}`);
return;
}
}
console.error(`could not find review${ID} in localStorage`);
}
// legacy function
export function getAllReviewsFromStorage() {
if (!(localStorage.getItem("activeIDS"))) {
// we wanna init the active ID array and start the nextID count
localStorage.setItem("activeIDS", JSON.stringify([]));
@@ -9,19 +69,10 @@ export function getReviewsFromStorage() {
}
//iterate thru activeIDS
let activeIDS = JSON.parse(localStorage.getItem("activeIDS"));
let reviews = []
let reviews = [];
for (let i = 0; i < activeIDS.length; i++) {
let currReview = JSON.parse(localStorage.getItem('review'+activeIDS[i]));
let currReview = JSON.parse(localStorage.getItem(`review${activeIDS[i]}`));
reviews.push(currReview);
}
return reviews;
}
/**
* Takes in an array of reviews, converts it to a string, and then
* saves that string to 'reviews' in localStorage
* @param {Array<Object>} reviews An array of reviews
*/
export function saveReviewsToStorage(reviews) {
localStorage.setItem(`review${reviewId}`, JSON.stringify(reviews));
}

View File

@@ -1,49 +1,103 @@
import {strict as assert} from "node:assert";
import {describe, it, beforeEach} from "mocha";
import {saveReviewsToStorage, getReviewsFromStorage} from "./localStorage.js";
import {describe, it, before, after} from "mocha";
import {newReviewToStorage, getReviewFromStorage, updateReviewToStorage, deleteReviewFromStorage, getAllReviewsFromStorage} from "./localStorage.js";
describe("test app localStorage interaction", () => {
beforeEach(() => {
before(() => {
localStorage.clear();
});
it("get after init", () => {
assert.deepEqual(getReviewsFromStorage(), []);
it("test localStorage state after init", () => {
assert.deepEqual(getAllReviewsFromStorage(), []);
assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), []);
assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 0);
});
it("store one then get", () => {
let reviews = [{
it("test localStorage state after adding one review", () => {
let review = {
"imgSrc": "sample src",
"imgAlt": "sample alt",
"mealName": "sample name",
"restaurant": "sample restaurant",
"rating": 5,
"tags": ["tag 1", "tag 2", "tag 3"]
}];
};
saveReviewsToStorage(reviews);
assert.deepEqual(getReviewsFromStorage(), reviews);
newReviewToStorage(review);
review.reviewID = 0;
assert.deepEqual(getAllReviewsFromStorage(), [review]);
assert.deepEqual(getReviewFromStorage(0), review);
assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), [0]);
assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 1);
});
it("repeated store one more and get", () => {
let reviews = [];
assert.deepEqual(getReviewsFromStorage(), reviews);
it("test localStorage state during adding 999 reviews", () => {
let reviews = getAllReviewsFromStorage();
let ids = [0];
for(let i = 0; i < 1000; i++){
reviews = getReviewsFromStorage();
reviews.push(
{
for(let i = 1; i < 1000; i++){
ids.push(i);
let new_review = {
"imgSrc": `sample src ${i}`,
"imgAlt": `sample alt ${i}`,
"mealName": `sample name ${i}`,
"restaurant": `sample restaurant ${i}`,
"rating": i,
"tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`]
};
newReviewToStorage(new_review);
new_review.reviewID = i;
reviews.push(new_review);
assert.deepEqual(getAllReviewsFromStorage(), reviews);
assert.deepEqual(getReviewFromStorage(i), new_review);
assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), ids);
assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), (i+1));
}
);
saveReviewsToStorage(reviews);
assert.deepEqual(getReviewsFromStorage(), reviews);
}).timeout(5000);
it("test localStorage state during updating 1000 reviews", () => {
let reviews = getAllReviewsFromStorage();
let ids = JSON.parse(localStorage.getItem("activeIDS"));
for(let i = 0; i < 1000; i++){
let new_review = {
"imgSrc": `updated sample src ${i}`,
"mealName": `updated sample name ${i}`,
"restaurant": `updated sample restaurant ${i}`,
"rating": i*2+i,
"tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`]
};
new_review.reviewID = i;
reviews[i] = new_review;
updateReviewToStorage(i, new_review);
assert.deepEqual(getAllReviewsFromStorage(), reviews);
assert.deepEqual(getReviewFromStorage(i), new_review);
assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), ids);
assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 1000);
}
}).timeout(10000);
}).timeout(5000);
it("test localStorage state during deleting 1000 reviews", () => {
let reviews = getAllReviewsFromStorage();
let ids = JSON.parse(localStorage.getItem("activeIDS"));
for(let i = 999; i >= 0; i--){
deleteReviewFromStorage(i);
ids.pop();
reviews.pop();
assert.deepEqual(getAllReviewsFromStorage(), reviews);
assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), ids);
assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 1000);
}
}).timeout(5000);
after(() => {});
});

View File

@@ -1,30 +1,231 @@
import {strict as assert} from "node:assert";
import {describe, it, beforeEach, afterEach} from "mocha";
import {describe, it, before, after} from "mocha";
import puppeteer from "puppeteer-core";
import {exit} from "node:process";
import {setReviewForm, checkCorrectness} from "./appTestHelpers.js";
describe("test App end to end", async () => {
let browser;
let page;
beforeEach(async () => {
browser = await puppeteer.launch();
page = await browser.newPage();
before(async () => {
let root;
try {
await page.goto("http://localhost:8080", {timeout: 1000});
root = process.getuid() == 0;
}
catch (error) {
console.log("❌ failed to connect to localhost webserver on port 8080");
exit(1);
root = false;
}
//browser = await puppeteer.launch({headless: false, slowMo: 250, args: root ? ['--no-sandbox'] : undefined});
browser = await puppeteer.launch({args: root ? ["--no-sandbox"] : undefined});
page = await browser.newPage();
try{
await page.goto("http://localhost:8080", {timeout: 2000});
await console.log(`✔ connected to localhost webserver as ${root ? "root" : "user"}`);
}
catch (error) {
await console.log("❌ failed to connect to localhost webserver on port 8080");
await exit(1);
}
});
describe("test simple properties", async () => {
it("page should have correct title", async () => {
assert.strictEqual(await page.title(), "Food Journal");
});
});
afterEach(async () => {
describe("test CRUD on simple inputs and default image", () => {
describe("test create 1 new review", async () => {
it("create 1 new review", async () => {
// Click the button to create a new review
let create_btn = await page.$("#create-btn");
await create_btn.click();
await page.waitForNavigation();
// create a new review
let review = {
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: 1
};
await setReviewForm(page, review);
// Click the save button to save updates
let save_btn = await page.$("#save-btn");
await save_btn.click();
await page.waitForNavigation();
});
it("check details page", async () => {
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/1-star.svg"
};
await checkCorrectness(page, "d", expected);
});
it("check home page", async () => {
// Click the button to return to the home page
let home_btn = await page.$("#home-btn");
home_btn.click();
await page.waitForNavigation();
// Get the review card again and get its shadowRoot
let review_card = await page.$("review-card");
let shadowRoot = await review_card.getProperty("shadowRoot");
let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/1-star.svg"
};
await checkCorrectness(shadowRoot, "a", expected);
});
});
describe("test read 1 review after refresh", async () => {
it("refresh page", async () => {
// Reload the page
await page.reload({ waitUntil: ["networkidle0", "domcontentloaded"] });
});
it("check details page", async () => {
// click review card
let review_card = await page.$("review-card");
await review_card.click();
await page.waitForNavigation();
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/1-star.svg"
};
await checkCorrectness(page, "d", expected);
});
it("check home page", async () => {
// Click the button to return to the home page
let home_btn = await page.$("#home-btn");
home_btn.click();
await page.waitForNavigation();
// Get the review card again and get its shadowRoot
let review_card = await page.$("review-card");
let shadowRoot = await review_card.getProperty("shadowRoot");
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/1-star.svg"
};
await checkCorrectness(shadowRoot, "a", expected);
});
});
describe("test update 1 review", async () => {
it("update 1 review", async () => {
// Get the only review card and click it
let review_card = await page.$("review-card");
await review_card.click();
await page.waitForNavigation();
// Click the button to show update form
let update_btn = await page.$("#update-btn");
await update_btn.click();
// create a new review
let review = {
mealName: "updated name",
comments: "updated comment",
restaurant: "updated restaurant",
tags: ["tag -0", "tag -1", "tag -2", "tag -3", "tag -4", "tag -5"],
rating: 5
};
await setReviewForm(page, review);
// Click the save button to save updates
let save_btn = await page.$("#save-btn");
await save_btn.click();
await page.waitForNavigation();
}).timeout(10000);
it("check details page", async () => {
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png",
mealName: "updated name",
comments: "updated comment",
restaurant: "updated restaurant",
tags: ["tag -0", "tag -1", "tag -2", "tag -3", "tag -4", "tag -5"],
rating: "http://localhost:8080/assets/images/5-star.svg"
};
await checkCorrectness(page, "d", expected);
});
it("check home page", async () => {
// Click the button to return to the home page
let home_btn = await page.$("#home-btn");
home_btn.click();
await page.waitForNavigation();
// Get the review card again and get its shadowRoot
let review_card = await page.$("review-card");
let shadowRoot = await review_card.getProperty("shadowRoot");
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png",
mealName: "updated name",
comments: "updated comment",
restaurant: "updated restaurant",
tags: ["tag -0", "tag -1", "tag -2", "tag -3", "tag -4", "tag -5"],
rating: "http://localhost:8080/assets/images/5-star.svg"
};
await checkCorrectness(shadowRoot, "a", expected);
});
});
describe("test delete 1 review", async () => {
it("delete 1 review", async () => {
// Get the only review card and click it
let review_card = await page.$("review-card");
await review_card.click();
await page.waitForNavigation();
page.on("dialog", async dialog => {
console.log(dialog.message());
await dialog.accept();
});
});
});
});
after(async () => {
await page.close();
await browser.close();
});

View File

@@ -1,12 +1,12 @@
// main.js
import {getReviewsFromStorage, saveReviewsToStorage} from "./localStorage.js";
import {getAllReviewsFromStorage} from "./localStorage.js";
// Run the init() function when the page has loaded
window.addEventListener("DOMContentLoaded", init);
function init() {
// Get the reviews from localStorage
let reviews = getReviewsFromStorage();
let reviews = getAllReviewsFromStorage();
// Add each reviews to the <main> element
addReviewsToDocument(reviews);
// Add the event listeners to the form elements
@@ -18,12 +18,12 @@ function init() {
* @param {Array<Object>} reviews An array of reviews
*/
function addReviewsToDocument(reviews) {
let mainEl = document.querySelector("main");
let reviewBox = document.getElementById("review-container");
reviews.forEach(review => {
let newReview = document.createElement("review-card");
newReview.data = review;
//TODO: want to append it to whatever the box is in layout
mainEl.append(newReview);
reviewBox.append(newReview);
});
}
@@ -39,85 +39,4 @@ function initFormHandler() {
createBtn.addEventListener("click", function(){
window.location.assign("./CreatePage.html");
});
//accessing form components
/*
let tagContainer = document.getElementById("tag-container-form");
let form = document.querySelector("form");
form.addEventListener("submit", function(){
/*
* User submits the form for their review.
* We create reviewCard and put in storage
let formData = new FormData(form);
let reviewObject = {};
for (let [key, value] of formData) {
console.log(`${key}`);
console.log(`${value}`);
if (`${key}` !== "tag-form") {
reviewObject[`${key}`] = `${value}`;
}
}
reviewObject["tags"] = [];
let tags = document.querySelectorAll(".tag");
for(let i = 0; i < tags.length; i ++) {
reviewObject["tags"].push(tags[i].innerHTML);
tagContainer.removeChild(tags[i]);
}
let newReview = document.createElement("review-card");
newReview.data = reviewObject;
//TODO: want to append it to whatever the box is in layout
let mainEl = document.querySelector("main");
mainEl.append(newReview);
// TODO: assign an ID to be used for referencing this object form the activeIDs array and the tag arrays
let ID = localStorage.nextID;
let storedReviews = getReviewsFromStorage();
storedReviews.push(reviewObject);
saveReviewsToStorage(storedReviews);
document.getElementById("new-food-entry").reset();
});
// DEV-MODE: for testing purposes
let clearBtn = document.querySelector(".danger");
clearBtn.addEventListener("click", function() {
localStorage.clear();
let mainEl = document.querySelector("main");
while (mainEl.firstChild) {
mainEl.removeChild(mainEl.firstChild);
}
let deleteTags = document.querySelectorAll(".tag");
for(let i = 0; i < deleteTags.length; i ++) {
tagContainer.removeChild(deleteTags[i]);
}
//clears reviews AS WELL as resets form
document.getElementById("new-food-entry").reset();
});
let tagAddBtn = document.getElementById("tagAdd");
tagAddBtn.addEventListener("click", ()=> {
let tagField = document.getElementById("tag-form");
if (tagField.value.length > 0) {
let tagLabel = document.createElement("label");
tagLabel.innerHTML = tagField.value;
tagLabel.setAttribute("class","tag");
tagLabel.addEventListener("click",()=> {
tagContainer.removeChild(tagLabel);
});
tagContainer.append(tagLabel);
tagField.value = "";
}
});
*/
}

View File

@@ -7,73 +7,51 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Food Journal</title>
<!--Add Favicon-->
<link rel="icon" type="image/x-icon" href="./assets/images/favicon.ico">
<!-- Recipe Card Custom Element -->
<script src="assets/scripts/ReviewCard.js" type="module"></script>
<!-- Main Stylesheets & Scripts -->
<!-- Temporarily commented out reset.css due to furthur discussion needed on the values of the default config-->
<!-- <link rel="stylesheet" href="/static/reset.css" /> -->
<link rel="stylesheet" href="./static/ReviewCard.css" />
<link rel="stylesheet" href="./static/homepage.css" />
<script src="assets/scripts/main.js" type="module"></script>
</head>
<body>
<header>
<div class="top-bar">
<img src ="./assets/images/Logo.png" alt="logo" />
<h1> Food Journal </h1>
<img src ="./assets/images/Logo.png" alt="logo" />
</div>
</header>
<main>
<!-- Add Food Entries Here -->
</main>
<button type="button" id="create-btn"><a href='./CreatePage.html'></a>CREATE</button>
<!-- <form id="new-food-entry">
<fieldset>
<legend>Pic:</legend>
<label for="mealImage">
Source:
<input type="text" id="mealImg" name="mealImg">
</label>
<label for="image-alt">
Alt Text:
<input type="text" id="imgAlt" name="imgAlt">
</label>
</fieldset>
<fieldset>
<legend> Meal: </legend>
<label for="Meal: ">Meal:
<input type="text" id="mealName" name="mealName" required>
</label>
<label for="comments">Comments:
<br>
<textarea name="comments" id="comments"></textarea>
</label>
</fieldset>
<fieldset class="rating">
<legend> Rating: </legend>
<input type="radio" id="s5" name="rating" value="5"/> <label for="s5"> 5 stars </label>
<input type="radio" id="s4" name="rating" value="4"/> <label for="s4"> 4 stars </label>
<input type="radio" id="s3" name="rating" value="3"/> <label for="s3"> 3 stars </label>
<input type="radio" id="s2" name="rating" value="2"/> <label for="s2"> 2 stars </label>
<input type="radio" id="s1" name="rating" value="1"/> <label for="s1"> 1 star </label>
</fieldset>
<fieldset>
<legend>Other Info:</legend>
<label for="restaurant">
Restaurant:
<input type="text" id="restaurant" name="restaurant" required>
</label>
<label for="tag-form">
Tags:
<input type="text" id="tag-form" name="tag-form">
<div class='tag-container' id="tag-container-form">
<div class="body-container">
<div style="width: 20%;"></div>
<div style="width: 60%;">
<div class="search-bar">
<form id="form">
<input type="search" id="searching" name="searchBar" placeholder="Search journal...">
<button class="click" type="search"> Search </button>
<div class="Filter-box">
</div>
<button type="button" id="tagAdd">Add Tag</button>
</label>
</form>
</div>
<div class="center-display">
<img src ="./assets/images/Grouppink.png" alt="CREATE" style="opacity: 100%;" id="create-btn" onclick="window.location.assign('./CreatePage.html')"/>
<h2 id="recent-reviews-text"> Recent Reviews </h2>
<img src ="./assets/images/Grouppink.png" style="opacity:0;"/>
</fieldset>
<button type="submit" value="Submit">Add Review</button>
<button type="button" class="danger">Clear Review Journal</button>
</form> -->
</div>
<div class="review-container" id="review-container"></div>
</div>
<div style="width: 20%;">
</div>
</div>
</main>
</body>
</html>

View File

@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Food Journal</title>
<script src="assets/scripts/reviewpage.js" type="module"></script>
</head>
<body>
<h1>Current Review:</h1>
<main>
</main>
</body>
</html>

View File

@@ -1,19 +0,0 @@
[
{
"imgSrc": "https://cdn.vox-cdn.com/thumbor/Cj5J-5WqSCjlC2tWCOXEB536CJY=/0x0:1810x1182/1200x800/filters:focal(761x447:1049x735)/cdn.vox-cdn.com/uploads/chorus_image/image/69422966/Tacos_Lined_Up.0.png",
"imgAlt": "tacos pic",
"mealName": "Birria Tacos",
"restaurant": "Mike's Red Tacos",
"rating": 5,
"tags": ["delicious", "#worthit","omg"]
},
{
"imgSrc": "https://www.redwormcomposting.com/images/worm-burrito.JPG",
"imgAlt": "wolftown pic",
"mealName": "Carnitas Burrito",
"restaurant": "Wolftown UCSD",
"rating": 0,
"tags": ["gross", "why","no"]
}
]

Binary file not shown.

View File

@@ -1,83 +1,30 @@
/* CreatePage.css */
* {
font-family: sans-serif;
@font-face {
font-family: testFont;
src: url("CoveredByYourGrace-Regular.ttf");
}
body {
height: 100%;
width: 100%;
background-color: #f8f3f1;
}
fieldset {
border: 2px solid rgb(214 214 214);
box-sizing: border-box;
display: block;
width: max-content;
}
form button {
display: block;
margin-top: 5px;
}
label[for="ingredients"] p {
margin: 0;
}
label[for="numRatings"] {
margin: 10px 0 0;
}
label[for^="rating"] {
padding-right: 10px;
}
label:not([for^="rating"]) {
display: block;
margin-bottom: 5px;
}
main {
column-gap: 10px;
.top-bar {
display: flex;
flex-wrap: wrap;
height: auto;
max-width: 660px;
row-gap: 10px;
width: 100%;
justify-content: center;
}
.tag-container {
display: flex;
flex-flow: row wrap;
.top-bar > img {
position: relative;
align-self: center;
padding-left: 2.5%;
padding-right: 2.5%;
}
.tag {
background-color: grey;
border-radius: 7px;
color: white;
padding-right: 7px;
padding-left: 7px;
margin: 3px;
}
.tag::before {
display: inline-block;
content: "x";
height: 15px;
width: 15px;
margin-right: 4px;
.top-bar > h1 {
position: relative;
text-align: center;
color: white;
cursor: pointer;
}
.tag:hover::before {
color: red;
}
.danger {
background-color: rgb(254 171 171);
border-color: red;
color: #516754;
font-size: 6rem;
font-family: testFont, sans-serif;
}

153
source/static/Form.css Normal file
View File

@@ -0,0 +1,153 @@
@font-face {
font-family: testFont;
src: url("CoveredByYourGrace-Regular.ttf");
}
.journal-form h1 {
font-family: testFont, sans-serif;
text-align: center;
}
.journal-form {
font-size: 120%;
font-family: "Century Gothic", sans-serif;
width: 50%;
margin: auto;
color: #516754;
border: 2px solid rgb(31 41 32);
border-radius: 8px;
background-color: #f7dfd5;
}
fieldset {
border: none;
}
input[type="text"] {
width: 100%;
box-sizing: border-box;
background-color: #f7dfd5;
border: none;
border-bottom: 1px solid rgb(0 0 0);
}
input[type="text"]:focus {
outline: none;
border-bottom: 1px solid rgb(0 0 0);
}
.rating {
display: flex;
flex-flow: nowrap row-reverse;
}
.hidden,
.rating:not(:checked) > input { /* Hide radio circles while star rating */
display: none;
}
/* Unchecked stars */
.rating:not(:checked) > label {
/* Make stars line up sideways and not vertically */
float: right;
/* Hide label text */
width: 1em;
overflow: hidden;
white-space: nowrap;
/* Star default color and size */
font-size: 200%;
line-height: 1.2;
color: #b3b3cc;
}
.rating > label:active {
position: relative;
}
.rating:not(:checked) > label::before {
content: "★";
}
/* Checked star color */
.rating > input:checked ~ label {
color: #ffbf00;
}
.rating:not(:checked) > label:hover,
.rating:not(:checked) > label:hover ~ label {
color: orangered;
}
.rating > input:checked + label:hover,
.rating > input:checked ~ label:hover,
.rating > input:checked + label:hover ~ label,
.rating > input:checked ~ label:hover ~ label,
.rating > label:hover ~ input:checked ~ label {
color: orangered;
}
.tag-container {
display: flex;
flex-flow: wrap row;
}
.tag {
background-color: grey;
border-radius: 7px;
color: white;
padding-right: 7px;
padding-left: 7px;
margin: 3px;
}
.tag::before {
display: inline-block;
content: "x";
height: 15px;
width: 15px;
margin-right: 4px;
text-align: center;
color: white;
cursor: pointer;
}
.tag:hover::before {
color: red;
}
#tag-add-btn {
background-color: #94da97; /* Green */
border: round;
color: rgb(206 83 179);
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 20px;
cursor: pointer;
border-radius: 10%;
margin-top: 5px;
}
#tag-add-btn:hover {
background-color: rgb(206 83 179); /* Green */
border: round;
color: #94da97;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 20px;
cursor: pointer;
border-radius: 10%;
margin-top: 5px;
}
.hidden {
display: none;
}
.tag-container * {
max-width: 100%;
overflow-wrap: anywhere;
}

93
source/static/OFL.txt Normal file
View File

@@ -0,0 +1,93 @@
Copyright (c) 2010, Kimberly Geswein (kimberlygeswein.com)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@@ -1,130 +0,0 @@
/* main.css */
* {
font-family: sans-serif;
}
body {
height: 100%;
width: 100%;
}
fieldset {
border: 2px solid rgb(214 214 214);
box-sizing: border-box;
display: block;
width: max-content;
}
form button {
display: block;
margin-top: 5px;
}
label[for="ingredients"] p {
margin: 0;
}
label[for="numRatings"] {
margin: 10px 0 0;
}
label[for^="rating"] {
padding-right: 10px;
}
label:not([for^="rating"]) {
display: block;
margin-bottom: 5px;
}
main {
column-gap: 10px;
display: flex;
flex-wrap: wrap;
height: auto;
max-width: 660px;
row-gap: 10px;
width: 100%;
}
.tag-container {
display: flex;
flex-flow: row wrap;
}
.tag {
background-color: grey;
border-radius: 7px;
color: white;
padding-right: 7px;
padding-left: 7px;
margin: 3px;
}
.tag::before {
display: inline-block;
content: "x";
height: 15px;
width: 15px;
margin-right: 4px;
text-align: center;
color: white;
cursor: pointer;
}
.tag:hover::before {
color: red;
}
.danger {
background-color: rgb(254 171 171);
border-color: red;
}
.hidden,
.rating:not(:checked) > input { /* Hide radio circles while star rating */
display: none;
}
/* Unchecked stars */
.rating:not(:checked) > label {
/* Make stars line up sideways and not vertically */
float: right;
/* Hide label text */
width: 1em;
overflow: hidden;
white-space: nowrap;
/* Star default color and size */
font-size: 200%;
line-height: 1.2;
color: #b3b3cc;
}
.rating > label:active {
position: relative;
}
.rating:not(:checked) > label::before {
content: "★";
}
/* Checked star color */
.rating > input:checked ~ label {
color: #ffbf00;
}
.rating:not(:checked) > label:hover,
.rating:not(:checked) > label:hover ~ label {
color: orangered;
}
.rating > input:checked + label:hover,
.rating > input:checked ~ label:hover,
.rating > input:checked + label:hover ~ label,
.rating > input:checked ~ label:hover ~ label,
.rating > label:hover ~ input:checked ~ label {
color: orangered;
}

View File

@@ -0,0 +1,45 @@
/* ReviewDetails.css */
@font-face {
font-family: testFont;
src: url("CoveredByYourGrace-Regular.ttf");
}
body {
background-color: #f8f3f1;
}
h1 {
text-align: center;
}
.top-bar {
display: flex;
justify-content: center;
}
.top-bar > img {
position: relative;
align-self: center;
padding-left: 2.5%;
padding-right: 2.5%;
}
.top-bar > h1 {
position: relative;
text-align: center;
/* color: #e4c3d2; */
color: #516754;
font-size: 6rem;
font-family: testFont, sans-serif;
}
.d-tag {
background-color: grey;
border-radius: 7px;
color: white;
padding-right: 7px;
padding-left: 7px;
margin: 10px;
}

View File

@@ -0,0 +1,93 @@
/* homepage.css */
@font-face {
font-family: testFont;
src: url("CoveredByYourGrace-Regular.ttf");
}
/* Color */
body {
/* background-color: #97a5bd */
/* background-color: #E3E3EC; */
background-color: #f8f3f1;
}
.top-bar {
display: flex;
justify-content: center;
}
.top-bar > img {
position: relative;
align-self: center;
padding-left: 2.5%;
padding-right: 2.5%;
}
.top-bar > h1 {
position: relative;
text-align: center;
/* color: #e4c3d2; */
/* color: rgb(145, 124, 175); */
color: #516754;
font-size: 6rem;
font-family: testFont, sans-serif;
}
.body-container {
display: flex;
max-height: 100%;
}
.center-display {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.search-bar {
display: flex;
justify-content: center;
}
.search-bar > form {
float: right;
padding: 6px 10px;
margin-top: 8px;
margin-right: 16px;
background: rgb(239 183 183);
font-size: 17px;
border: none;
border-radius: 12px;
cursor: pointer;
}
#recent-reviews-text {
text-align: center;
font-size: 4rem;
color: #516754;
font-family: testFont, sans-serif;
}
img#create-btn {
position: relative;
align-self: center;
padding-left: 2.5%;
padding-right: 2.5%;
}
.review-container {
display: flex;
position: relative;
flex-wrap: wrap;
justify-content: center;
}
.review-container > div {
background-color: #f1f1f1;
text-align: center;
}

View File

@@ -1,158 +0,0 @@
/* This is a generic CSS file that sets preliminary rules for content that should be the same across pages */
html,
body,
div,
span,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
abbr,
address,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
samp,
small,
strong,
sub,
sup,
var,
b,
i,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
body {
line-height: 1;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
nav ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote::before,
blockquote::after,
q::before,
q::after {
content: "";
content: none;
}
a {
margin: 0;
padding: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
input,
select {
vertical-align: middle;
}
img,
fieldset,
object {
border: none;
}
*,
*::after,
*::before {
box-sizing: border-box;
}
button,
label {
cursor: pointer;
}
html,
body {
height: 100%;
}
form {
border: solid;
}

View File

@@ -0,0 +1,19 @@
# Use Stylelint for CSS linting framework
- Status: accept
- Deciders: Arthur Lu, Marc Reta
- Date: 11 / 14 / 22
## Decision Drivers
- Need linting to work with multiple style standards
- Need linting to be fast and informative
## Considered Options
- Stylelint
- Prettier
## Decision Outcome
Chosen Option: Stylelint for its easy installation and unopinionated.

View File

@@ -0,0 +1,19 @@
# Use HTMLhint for HTML linting framework
- Status: accept
- Deciders: Arthur Lu, Marc Reta
- Date: 11 / 14 / 22
## Decision Drivers
- Need linting to work with multiple style standards
- Need linting to be fast and informative
## Considered Options
- HTMLhint
- HTML-validate
## Decision Outcome
Chosen Option: HTMLhint for its low configuration complexity.