Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
288 commits
Select commit Hold shift + click to select a range
7cde89c
added likebutton, loppis placeholder image, and fixed basic styling i…
mimmi-eriksson Aug 8, 2025
48c58af
fixed error with trying to map undefined categories before fetch is f…
mimmi-eriksson Aug 8, 2025
cea1073
cleanup
MalLunBar Aug 8, 2025
d6ab50d
Merge branch 'main' of https://github.com/MalLunBar/project-final
mimmi-eriksson Aug 8, 2025
95c29e7
changed userform to login form and cleaned up
mimmi-eriksson Aug 8, 2025
c713e6f
make fetch for adding a loppis
MalLunBar Aug 8, 2025
aab896a
styling login-page and fixed input component
mimmi-eriksson Aug 8, 2025
13d4bbe
small style fixes login-page
mimmi-eriksson Aug 8, 2025
2262e18
chnage so that date and times are seperate.
MalLunBar Aug 8, 2025
fe9a8fd
cleanup
MalLunBar Aug 8, 2025
bb93d00
Merge branch 'main' of https://github.com/MalLunBar/project-final
mimmi-eriksson Aug 11, 2025
8feae2b
created mapview, installed leaflet and react-leaflet, and added mapco…
mimmi-eriksson Aug 11, 2025
4a06d25
added markers to test map
mimmi-eriksson Aug 11, 2025
e728338
changed z-index on header to show on top of map container
mimmi-eriksson Aug 11, 2025
e12347f
testing cluster in map view
mimmi-eriksson Aug 11, 2025
92bc575
updated loppis model and added updated json file with start data
mimmi-eriksson Aug 11, 2025
406aa5a
seeding updated data to database
mimmi-eriksson Aug 11, 2025
bd1d9f1
updated loppisCard to display updated info
mimmi-eriksson Aug 11, 2025
69ee516
add geocode to serch for city, functions to mapview, and proxy to bac…
MalLunBar Aug 11, 2025
16a0164
Merge branch 'main' of https://github.com/MalLunBar/project-final
mimmi-eriksson Aug 12, 2025
3a251d6
updated loppisInfo page to show updated info
mimmi-eriksson Aug 12, 2025
e5ad4ef
updated search page and mapview to show loppises on map
mimmi-eriksson Aug 12, 2025
d2f7630
change title
MalLunBar Aug 12, 2025
73fdeba
styling cluster and loppiscard
MalLunBar Aug 12, 2025
4a7f767
chnge position of zoom on map
MalLunBar Aug 12, 2025
c0cf304
started updating addLoppis page to fit updated loppis model, added sm…
mimmi-eriksson Aug 12, 2025
d31192d
small style fix in addLoppis page and Button component
mimmi-eriksson Aug 12, 2025
ec3b2c4
updated handleSubmit in addLoppis page, added pre-save hook to automa…
mimmi-eriksson Aug 12, 2025
582184f
style fix in addLoppis page
mimmi-eriksson Aug 12, 2025
f66f265
Merge branch 'add-loppis'
mimmi-eriksson Aug 12, 2025
945b87f
styling of top navigation
mimmi-eriksson Aug 13, 2025
f5f0d96
styling hamburger menu and menu
mimmi-eriksson Aug 13, 2025
f47dfb7
cleanup and put primary font in css file
MalLunBar Aug 13, 2025
4c5cfd8
changed z-index on backdrop overlay
mimmi-eriksson Aug 13, 2025
887429e
Merge branch 'loginModal'
mimmi-eriksson Aug 13, 2025
d86f45a
add endpoint for edit, delete and like
MalLunBar Aug 13, 2025
709ec31
changed layout on search page, added listView component
mimmi-eriksson Aug 13, 2025
0c74040
add endpoint and fetch for loppisar made from a specific user
MalLunBar Aug 13, 2025
f44bd19
added filterOptions component
mimmi-eriksson Aug 13, 2025
6d63ce6
in filte options set search field input to not required
mimmi-eriksson Aug 13, 2025
1e48fd7
add createdBy to Add Loppis to get userId
MalLunBar Aug 13, 2025
d66945d
fix bug for not getting id
MalLunBar Aug 13, 2025
a1ac14e
lifting query state to searchFilters
mimmi-eriksson Aug 14, 2025
b04a60c
added searchfilters to mobile view
mimmi-eriksson Aug 14, 2025
6225c3c
change loppisList and LoppisCard to decide the look and funktionality…
MalLunBar Aug 14, 2025
a4a1820
More elements to deal with edit, delete and close and add another edi…
MalLunBar Aug 14, 2025
8b64bec
added search filters as toggle menu for mobile
mimmi-eriksson Aug 14, 2025
83849f3
positioning mobile toggle buttons on top of map
mimmi-eriksson Aug 14, 2025
2c76610
fixed responsiveness for mobile toggle buttons
mimmi-eriksson Aug 14, 2025
f6fd8a6
displaying selected filters on map
mimmi-eriksson Aug 14, 2025
e46484c
Break out LoppisForm, Create EditModal, Change related components/pag…
MalLunBar Aug 14, 2025
052cf12
updating listView with listLength and placeholder for sorting options
mimmi-eriksson Aug 14, 2025
564d982
positioning toggle buttons above listView
mimmi-eriksson Aug 14, 2025
8bd76b0
fixed z index for filter menu
mimmi-eriksson Aug 14, 2025
6d47fd1
add deleteLoppis functionality
MalLunBar Aug 14, 2025
4f177ed
added logic for filtering in get loppis endpoint
mimmi-eriksson Aug 14, 2025
4ee7aef
added query params to loppis fetch
mimmi-eriksson Aug 14, 2025
bb42ab7
fixed search page - filtering now sends the correct fetch to backend
mimmi-eriksson Aug 15, 2025
98eb1b0
Merge branch 'search-filtering'
mimmi-eriksson Aug 15, 2025
0b3f088
changed to case-insensitive partial match on the address.city field i…
mimmi-eriksson Aug 15, 2025
a727b06
add a package
MalLunBar Aug 15, 2025
479176c
created like model and updated loppis model with likes
mimmi-eriksson Aug 15, 2025
6694465
Add component to upload photo and include in LoppisForm
MalLunBar Aug 15, 2025
3a26513
created authorization middleware and updated like loppis endpoint so …
mimmi-eriksson Aug 15, 2025
e5f6d4d
created endpoint to list a users liked loppises
mimmi-eriksson Aug 15, 2025
7a9c7eb
added authentication to get all loppises by a specific user
mimmi-eriksson Aug 15, 2025
166eec9
change backend accept imge urls. start cloudinary
MalLunBar Aug 15, 2025
f1739e0
added like function to send like request to backend on loppisCard
mimmi-eriksson Aug 18, 2025
542b511
Connected images to cloudinary
MalLunBar Aug 18, 2025
db1891b
updated like endpoint response with action
mimmi-eriksson Aug 18, 2025
62ab1ba
Clean up after change of Loppis model. Styling and prepping LoppisInfo
MalLunBar Aug 18, 2025
a643597
add images for styling
MalLunBar Aug 18, 2025
8b87f71
some styling and make sure images show correctly during edit
MalLunBar Aug 19, 2025
c064c78
useMmo to stop infinite loop
MalLunBar Aug 19, 2025
56a9be6
updated profile page with sections MyLoppis and MyFavorites
mimmi-eriksson Aug 19, 2025
81e1984
styling
MalLunBar Aug 19, 2025
5c244be
updated with likedLoppis state to reflect if a user has already liked…
mimmi-eriksson Aug 19, 2025
83c308a
positioning
MalLunBar Aug 19, 2025
c742664
changed empty message in favorites
mimmi-eriksson Aug 19, 2025
91441df
Merge branch 'likeLoppis'
mimmi-eriksson Aug 19, 2025
bcbd2c5
styling
MalLunBar Aug 19, 2025
6d333d4
added redirection to details page after adding loppis in addloppis page
mimmi-eriksson Aug 20, 2025
1040bfa
created likesStore and likesApi in services and implemented useLikesS…
mimmi-eriksson Aug 20, 2025
66620a3
created authApi in services to handle login and register API calls
mimmi-eriksson Aug 20, 2025
27bb427
updated login modal to use authStore to log in
mimmi-eriksson Aug 20, 2025
2bc23a7
updated register page to use authStore to register user
mimmi-eriksson Aug 20, 2025
13c287a
fixed typo in register page
mimmi-eriksson Aug 20, 2025
adfe15c
added helper to clear error when register page or login modal mounts
mimmi-eriksson Aug 20, 2025
6693b5b
Use leaflets location to both find loppises near me but also se my lo…
MalLunBar Aug 20, 2025
5f916de
started updating endpoint and services structure
mimmi-eriksson Aug 20, 2025
ee4c39c
fixing imports in userRoutes
mimmi-eriksson Aug 20, 2025
8d5de60
updating MyFavorites to use LikeStore
mimmi-eriksson Aug 20, 2025
735f50c
updated loppisCard to use likesStore and removed all old local likeLo…
mimmi-eriksson Aug 20, 2025
e92dfd8
Added onRehydrateStorage to the Zustand persist middleware in AuthSto…
mimmi-eriksson Aug 21, 2025
36660dd
updated loppisApi with call to get one loppis by id and used that in …
mimmi-eriksson Aug 21, 2025
6526601
Merge branch 'location'
MalLunBar Aug 21, 2025
15d26b3
updated loppisApi with deleteLoppis function and used that in MyLoppi…
mimmi-eriksson Aug 21, 2025
e30d086
updated loppisApi with getLoppisList function and used it in SearchPage
mimmi-eriksson Aug 21, 2025
5060f6e
created geogodingApi service and used geocodeCity in search page
mimmi-eriksson Aug 21, 2025
5b615ac
added reverse geocoding route in backend and in geocodeApi in services
mimmi-eriksson Aug 21, 2025
64fe9ce
added createLoppis function for api call in loppisApi and using it in…
mimmi-eriksson Aug 21, 2025
feb2276
added getLoppisCategories function to loppisApi and using it in loppi…
mimmi-eriksson Aug 21, 2025
254365c
using getLoppisCategories to fetch category options in search filters
mimmi-eriksson Aug 21, 2025
faf1238
created updateLoppis function in loppisApi and using in editModal
mimmi-eriksson Aug 21, 2025
f4917f0
Merge branch 'services'
mimmi-eriksson Aug 21, 2025
99e118f
change of navbar
MalLunBar Aug 21, 2025
53dbe2d
Add route parameters for Profile CardLinks
MalLunBar Aug 21, 2025
f6e7200
Merge branch 'profile-new'
MalLunBar Aug 21, 2025
8efb929
creating hero section with search bar at home page
mimmi-eriksson Aug 22, 2025
6be37da
testing layout homePage
mimmi-eriksson Aug 22, 2025
e88aefe
continue styling example layout homePage
mimmi-eriksson Aug 22, 2025
2e06902
creating heroSearch and SearchBar component, updating Search page to …
mimmi-eriksson Aug 22, 2025
7b48892
created categoryGrid and updated search page to take category query p…
mimmi-eriksson Aug 22, 2025
cd05737
Fix edit bug
MalLunBar Aug 22, 2025
7187768
added funcions to fetch popular loppis and list in the carousel
mimmi-eriksson Aug 22, 2025
c3c4c84
fixed styling of carouselcard
mimmi-eriksson Aug 22, 2025
2c91155
Merge branch 'homePage'
mimmi-eriksson Aug 22, 2025
ef92f87
add protected page and some styling
MalLunBar Aug 22, 2025
2b605c2
authentication for all relevant links
MalLunBar Aug 22, 2025
59b080c
clean up
MalLunBar Aug 22, 2025
f0e5c0f
fixing layout searchPage and adding layout component
mimmi-eriksson Aug 25, 2025
5a4e012
Merge branch 'profile-settings'
MalLunBar Aug 25, 2025
c42b06b
layout mobile control panel
mimmi-eriksson Aug 25, 2025
173951d
add more background images
MalLunBar Aug 25, 2025
c7fccfe
fixing search page to trigger correct fetch from search query params
mimmi-eriksson Aug 25, 2025
1c58cea
updated searchpage and searchfilters to be url-driven and always alwa…
mimmi-eriksson Aug 25, 2025
5b155ec
error handeling
MalLunBar Aug 25, 2025
f90a851
Add manuitem
MalLunBar Aug 25, 2025
73ee30b
Make sure you can add an image and make it a coverimage at the same t…
MalLunBar Aug 25, 2025
fa0c485
Start of the about page
MalLunBar Aug 25, 2025
12d21f5
restructuring search page, adding reset filters button, and handling …
mimmi-eriksson Aug 25, 2025
5e2a9f9
updating reset filters to clear city searchfield
mimmi-eriksson Aug 25, 2025
95a1ed5
cleaning
mimmi-eriksson Aug 25, 2025
a4cb53c
Merge branch 'search'
mimmi-eriksson Aug 26, 2025
9325512
small fix: positioning navbar, spacing login modal, profilePage page …
mimmi-eriksson Aug 26, 2025
14a301c
loppisInfo page - fixed like button and added back button
mimmi-eriksson Aug 26, 2025
420c6df
Merge branch 'main' of https://github.com/MalLunBar/project-final
MalLunBar Aug 26, 2025
96f949c
styling profile
MalLunBar Aug 26, 2025
a193548
Move images to be able to reach them from everywhere and fix backgrou…
MalLunBar Aug 26, 2025
bb56fe6
responsive styling loppis info page
mimmi-eriksson Aug 26, 2025
90437aa
added function to show distance to loppis if user has granted location
mimmi-eriksson Aug 26, 2025
c899f12
Merge branch 'loppis-info'
mimmi-eriksson Aug 26, 2025
d183c21
added logic and navigation if save to favorites button is clicked in …
mimmi-eriksson Aug 26, 2025
31eb4f8
added link to loppisInfo page when clicking title in carouselcard
mimmi-eriksson Aug 26, 2025
69053c7
fixed issue with squeezed cards on mount in the popular loppis carousel
mimmi-eriksson Aug 26, 2025
d2fe572
styling and positioning of tabs
MalLunBar Aug 26, 2025
d21ae7a
added upcoming endpoint and fetch to display upcoming loppis in home …
mimmi-eriksson Aug 26, 2025
e517367
small style fix in loppis ifo page
mimmi-eriksson Aug 26, 2025
c8933cf
move logo to get imga to show all the time
MalLunBar Aug 26, 2025
97a6b76
Merge branch 'positioning'
MalLunBar Aug 26, 2025
0525a7c
move images
MalLunBar Aug 26, 2025
3ae36fa
change image path on home
MalLunBar Aug 26, 2025
44ae6ed
Create sections for our about-page
MalLunBar Aug 26, 2025
f4d5dbe
About us page fix
MalLunBar Aug 26, 2025
3f99a44
signup page styling
MalLunBar Aug 26, 2025
d4d483a
not found page
MalLunBar Aug 26, 2025
9e9c78d
delete leaflet default styling
MalLunBar Aug 26, 2025
4c602e9
change menuitem "logga in" to button
MalLunBar Aug 26, 2025
c71b388
clearing liked loppis list on logout
mimmi-eriksson Aug 26, 2025
29d1433
fixing bug with login modal popping up on logout, removing console lo…
mimmi-eriksson Aug 26, 2025
e06f185
fixed height on search, profile and not found to take up full screen …
mimmi-eriksson Aug 27, 2025
d643be4
added base in vite config
mimmi-eriksson Aug 27, 2025
74fbdaa
Fix headers for Netlify deployment
mimmi-eriksson Aug 27, 2025
5a5cf0b
reset changes for deployment issue
mimmi-eriksson Aug 27, 2025
bbdd682
Co-authored-by: Mimmi Eriksson <mimmi.aj.eriksson@gmail.com>
MalLunBar Aug 27, 2025
5ff6b65
added favicon
mimmi-eriksson Aug 27, 2025
9687e71
Merge branch 'main' of https://github.com/MalLunBar/project-final
mimmi-eriksson Aug 27, 2025
cdb314c
add more background images
MalLunBar Aug 27, 2025
7c004aa
setting up environment variables with api urls for local dev and prod
mimmi-eriksson Aug 27, 2025
a7a9ced
Merge branch 'main' of https://github.com/MalLunBar/project-final
mimmi-eriksson Aug 27, 2025
0813a8d
delete bottomnav
MalLunBar Aug 27, 2025
e359ac7
add more to color scheme
MalLunBar Aug 27, 2025
4692130
change button colors
MalLunBar Aug 27, 2025
97f70c2
fix
MalLunBar Aug 27, 2025
df94ef0
fix
MalLunBar Aug 27, 2025
33b14e0
created section divider component
mimmi-eriksson Aug 27, 2025
b805343
styling herosearch and searchbar
mimmi-eriksson Aug 27, 2025
3e36380
styling home and ctaHome
mimmi-eriksson Aug 27, 2025
22ac6b6
styling
MalLunBar Aug 27, 2025
590979a
Change button on profile/loppisar
MalLunBar Aug 27, 2025
1c69f75
finished styling home page and sections, and improved accessibility
mimmi-eriksson Aug 27, 2025
65a4028
fixing styling and accessibility on loppisInfo page, including likeBu…
mimmi-eriksson Aug 28, 2025
d1ebfa4
fix background, positioning, space and editingbutton
MalLunBar Aug 28, 2025
6bc1cd6
fix search page, styling, accessibility, including mounted components…
mimmi-eriksson Aug 28, 2025
fc4cb6a
semitransparent background and backdrop-blur in LoppisInfo page
mimmi-eriksson Aug 28, 2025
905423f
skip to main content link in TopNav and main id on all pages
mimmi-eriksson Aug 28, 2025
cdee011
styling
MalLunBar Aug 28, 2025
414c6b3
Merge branch 'background-style'
MalLunBar Aug 28, 2025
20bba61
focus management mobile menu
mimmi-eriksson Aug 28, 2025
d566105
focus visible styling of menu items and links
mimmi-eriksson Aug 28, 2025
f5e5301
styled active link
mimmi-eriksson Aug 28, 2025
b877be4
added a ScrollToTopAndFocus component that listens to rout changes an…
mimmi-eriksson Aug 28, 2025
fbcca62
added AriaLiveRegion component to announce for screen readers when a …
mimmi-eriksson Aug 28, 2025
6aee02e
Merge branch 'nav-access'
mimmi-eriksson Aug 28, 2025
44ecfce
focus management login modal
mimmi-eriksson Aug 28, 2025
d87639a
change readme and check lighthouse on every page
MalLunBar Aug 28, 2025
24e4b75
login modal change focus order
mimmi-eriksson Aug 28, 2025
f6a19f7
Merge branch 'lighthouse'
MalLunBar Aug 28, 2025
daa5d4d
style links on aboutPage
mimmi-eriksson Aug 28, 2025
e2614e1
chnage image
MalLunBar Aug 28, 2025
34eb38f
Cleanup
MalLunBar Aug 28, 2025
ab6c705
changed default center and zoom on mapView
mimmi-eriksson Aug 28, 2025
891e47e
added placeholder grey box if no image on CarouselCard and LoppisInfo
mimmi-eriksson Aug 28, 2025
dd8b5aa
adjusting default center and zoom
mimmi-eriksson Aug 28, 2025
246555f
cleaning
mimmi-eriksson Aug 28, 2025
47b50c9
Merge branch 'demo-fix'
mimmi-eriksson Aug 28, 2025
0bbcce0
credits to artist in readme
MalLunBar Aug 28, 2025
efec359
fixed search bar responsiveness
mimmi-eriksson Aug 30, 2025
5ce8a2e
changing page height to use dvh and safe areas insets on profile, sea…
mimmi-eriksson Aug 30, 2025
f4681f0
fixing page height on search
mimmi-eriksson Aug 30, 2025
7bfb8f2
new try to fix page height using dvh and safe area insets on all pages
mimmi-eriksson Aug 30, 2025
ba5a763
added gap in upcoming loppis card
mimmi-eriksson Aug 30, 2025
b806b88
adding fake placeholder for dat and time inputs on mobile, responsivn…
mimmi-eriksson Aug 30, 2025
683f8b1
added filtertags to display selected filters in loppisform
mimmi-eriksson Aug 30, 2025
9d53c88
fixed layout of date and time inputs for mobile
mimmi-eriksson Aug 30, 2025
c3f59db
created a netlify.toml file to handle rediricting all routes to index…
mimmi-eriksson Aug 30, 2025
e1ba40d
adjusting responsiveness on date time inputs for mobile
mimmi-eriksson Aug 30, 2025
3c1bc79
added sortin on text on loppis list view
mimmi-eriksson Aug 30, 2025
f5f1c8d
all buttons and links have cursor-pointer and hover effect
mimmi-eriksson Aug 30, 2025
68ee439
checking loading states
mimmi-eriksson Aug 30, 2025
6c097d2
structure up a bit
MalLunBar Aug 30, 2025
3dbb012
contact page + update loading at home page
MalLunBar Aug 30, 2025
d8248e4
add loader to MyLoppises but cleanup on MyFavourites
MalLunBar Aug 30, 2025
cf0eca2
loader for when images is updated to cover image
MalLunBar Aug 30, 2025
26066ec
Cleanup of edit modal for inputs not to stretch outside of form.
MalLunBar Aug 31, 2025
8d44c1f
change error for login and add error messages.
MalLunBar Aug 31, 2025
e6de300
add error for search page when city not found
MalLunBar Aug 31, 2025
df59513
import useNavigate in CtaHome
mimmi-eriksson Aug 31, 2025
cb6a8ad
displaying a empty message if no upcoming loppis in Upcoming
mimmi-eriksson Aug 31, 2025
903386e
emptymessage in favorite loppises section on home page
mimmi-eriksson Aug 31, 2025
9a25a57
added loader for heroImage in LoppisInfo
mimmi-eriksson Aug 31, 2025
c3bd591
make loppiscard smaller om mobile
MalLunBar Aug 31, 2025
072ff3c
added loader on gallery images
mimmi-eriksson Aug 31, 2025
55dd233
added loader to listView on Search
mimmi-eriksson Aug 31, 2025
8b8043e
added loader to mapView on Search
mimmi-eriksson Aug 31, 2025
d924cad
cleaning server file
mimmi-eriksson Aug 31, 2025
c341749
style for everything to fit on mapview
MalLunBar Aug 31, 2025
e20a3f9
setting up swagger for API documentation and creating comments for us…
mimmi-eriksson Aug 31, 2025
e133079
adding swagger comments for geocoding routes
mimmi-eriksson Aug 31, 2025
1aac2d6
error messages in register form
MalLunBar Aug 31, 2025
d40b6f0
added swagger comments for all routes
mimmi-eriksson Aug 31, 2025
6d1875a
added swagger for API doc in readme
mimmi-eriksson Aug 31, 2025
e69273c
cleaning
mimmi-eriksson Aug 31, 2025
4353dd5
hiding slider arrows during loading in popular Carousel
mimmi-eriksson Aug 31, 2025
845eb48
cleaning
mimmi-eriksson Aug 31, 2025
ae9d3a1
error handling
MalLunBar Aug 31, 2025
6f64082
Merge branch 'error-branch'
MalLunBar Aug 31, 2025
464191b
typo
MalLunBar Sep 1, 2025
6b6ffc9
add an og link
MalLunBar Sep 2, 2025
b272f96
Chnage position of formelement on mobile and fix errormessage showing…
MalLunBar Dec 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
# Final Project

Replace this readme with your own information about your project.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
A full-stack web application where users can discover and create flea markets (“loppis”) nearby. The app allows people to browse events on a map, add their own flea markets with details and images, and interact with the community.

## The problem

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
We wanted to make it easier for people to find and share local flea markets in a simple and user-friendly way. To achieve this, we built a responsive web app with the following approach:

- **Planning:** We started by breaking down the project into core features, user registration & login, map integration, creating new flea markets, and browsing events. We also created a design in figma and a flowchart.

- **Frontend:** Built with React, Tailwind CSS, React Router, Zustand, and Leaflet for interactive maps. We also used libraries for e.g. keen-slider, react focus lock and then lucide for icons.

- **Backend:** Node.js with Express, MongoDB (Atlas) for data storage, Nominatim API for Open Source Street Map and Cloudinary for image handling. Swagger/OpenAPI for API documentation. Also other libraries like multer to be able to handle formdata submittion with different file formats.

- **Techniques:** We focused on reusable components, clean state management with hooks, and a mobile-first design.

- **Next steps:**
With more time, we would like to:
- Allow users to upload a profile picture, edit contact information, and choose dark mode.
- Automatically filter out flea markets with past dates.
- Add more flexible scheduling options when creating an event, e.g. “every Sunday until further notice.”
- Let users click “add to calendar” so their calendar app opens with the flea market details pre-filled.
- Improve the user experience with more transitions and animations.
- Implement a global error handler to manage larger issues such as network failures.

# Credits

- [Bianca Van Dijk](https://pixabay.com/users/biancavandijk-9606149/) – images from Pixabay

## View it live

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
[Live demo on Netlify]
https://runthornet.netlify.app/


[Backend on Render]
https://runthornet-api.onrender.com/
22 changes: 22 additions & 0 deletions backend/middleware/authMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { User } from "../models/User.js"

export const authenticateUser = async (req, res, next) => {
try {
const accessToken = req.header("Authorization")
const user = await User.findOne({ accessToken: accessToken })
if (user) {
req.user = user
next()
} else {
res.status(401).json({
message: "Authentication missing or invalid.",
loggedOut: true
})
}
} catch (error) {
res.status(500).json({
message: "Internal server error",
error: error.message
});
}
}
23 changes: 23 additions & 0 deletions backend/models/Like.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import mongoose from "mongoose"

const likeSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
loppis: {
type: mongoose.Schema.Types.ObjectId,
ref: "Loppis",
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})

// Ensure that a user can only like a loppis once
likeSchema.index({ user: 1, loppis: 1 }, { unique: true })

export const Like = mongoose.model("Like", likeSchema)
114 changes: 114 additions & 0 deletions backend/models/Loppis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import mongoose from 'mongoose'

const loppisSchema = new mongoose.Schema({
title: {
type: String,
required: true,
minLength: 5,
maxLength: 50
},
location: {
address: {
street: String,
city: String,
postalCode: String,
country: {
type: String,
default: 'Sweden'
}
},
coordinates: {
type: {
type: String,
enum: ['Point'],
default: 'Point'
},
coordinates: {
type: [Number], // [longitude, latitude]
required: true
},
},
},
dates: [
{
date: {
type: Date,
required: true
},
startTime: {
type: String, // HH:MM format
required: true
},
endTime: {
type: String, // HH:MM format
required: true
}
}
],
categories: {
type: [String],
required: true,
enum: [
"Vintage",
"Barn",
"Trädgård",
"Kläder",
"Möbler",
"Böcker",
"Husdjur",
"Elektronik",
"Kök",
"Blandat"
],
default: "Blandat"
},
description: {
type: String,
maxLength: 500
},
likes: {
type: Number,
default: 0,
min: 0
},
images: [{ type: String }], // bara public_id
coverImage: { type: String }, // public_id
createdAt: {
type: Date,
default: Date.now
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
})

// Pre-save hook to automatically geocode address
loppisSchema.pre('save', async function (next) {
if (this.isModified('location.address')) {

const { street, city, postalCode } = this.location.address
const query = `${street}, ${postalCode} ${city}, Sweden`

try {
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}&limit=1`
const response = await fetch(url)
const data = await response.json()

if (data.length > 0) {
const { lat, lon } = data[0]
this.location.coordinates = {
type: 'Point',
coordinates: [parseFloat(lon), parseFloat(lat)]
}
} else {
throw new Error('Address not found')
}
} catch (error) {
return next(error)
}
}
next()
})

export const Loppis = mongoose.model('Loppis', loppisSchema)
27 changes: 27 additions & 0 deletions backend/models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import mongoose from "mongoose"
import crypto from "crypto"

const userSchema = new mongoose.Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
accessToken: {
type: String,
default: () => crypto.randomBytes(128).toString("hex")
}
})

export const User = mongoose.model("User", userSchema)
13 changes: 11 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,18 @@
"@babel/core": "^7.17.9",
"@babel/node": "^7.16.8",
"@babel/preset-env": "^7.16.11",
"bcrypt-nodejs": "^0.0.3",
"cloudinary": "^2.7.0",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"express": "^4.17.3",
"express-list-endpoints": "^7.1.1",
"luxon": "^3.7.1",
"mongoose": "^8.4.0",
"nodemon": "^3.0.1"
"multer": "^2.0.2",
"nodemon": "^3.0.1",
"sharp": "^0.34.3",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1"
}
}
}
137 changes: 137 additions & 0 deletions backend/routes/geocodeRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import express from "express"

const router = express.Router()

// Swagger
/**
* @openapi
* tags:
* name: Geocoding
* description: Endpoints for converting between addresses and geographic coordinates using OpenStreetMap Nominatim.
*/

// Forward geocoding route
/**
* @openapi
* /api/geocode:
* get:
* tags:
* - Geocoding
* summary: Forward geocode an address or place
* description: Uses OpenStreetMap Nominatim to convert an address or place name into coordinates.
* parameters:
* - in: query
* name: q
* required: true
* schema:
* type: string
* description: Search query (address, place name, etc.)
* responses:
* 200:
* description: Geocoding result
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* 400:
* description: Missing query parameter
* 500:
* description: Upstream error
*/
router.get("/", async (req, res) => {
const q = req.query.q
if (!q) return res.status(400).json({ error: "Missing q" })

// Build Nominatim URL
const url = new URL("https://nominatim.openstreetmap.org/search")
url.searchParams.set("q", String(q))
url.searchParams.set("format", "json")
url.searchParams.set("limit", "1")
url.searchParams.set("addressdetails", "1")
url.searchParams.set("countrycodes", "se")

try {
const r = await fetch(url, {
headers: {
// Required by Nominatim policy: identify your app + contact
"User-Agent": `LoppisApp/1.0 (${process.env.GEOCODER_CONTACT ?? "malinelundgren1991@gmail.com"})`,
"Accept": "application/json",
},
})
if (!r.ok) {
return res.status(r.status).json({ error: "Geocoding failed" })
}
const data = await r.json()
res.json(data)
} catch (e) {
console.error("Geocode proxy error:", e)
res.status(500).json({ error: "Upstream error" })
}
})

// Reverse geocoding route
/**
* @openapi
* /api/geocode/reverse:
* get:
* tags:
* - Geocoding
* summary: Reverse geocode coordinates
* description: Uses OpenStreetMap Nominatim to convert latitude/longitude into a human-readable address.
* parameters:
* - in: query
* name: lat
* required: true
* schema:
* type: number
* description: Latitude
* - in: query
* name: lon
* required: true
* schema:
* type: number
* description: Longitude
* responses:
* 200:
* description: Reverse geocoding result
* content:
* application/json:
* schema:
* type: object
* 400:
* description: Missing coordinates
* 500:
* description: Upstream error
*/
router.get("/reverse", async (req, res) => {
const { lat, lon } = req.query
if (!lat || !lon) return res.status(400).json({ error: "Missing coordinates" })

// Nominatim URL
const url = new URL("https://nominatim.openstreetmap.org/reverse")
url.searchParams.set("lat", lat)
url.searchParams.set("lon", lon)
url.searchParams.set("format", "json")

try {
const r = await fetch(url, {
headers: {
// Required by Nominatim policy: identify your app + contact
"User-Agent": `LoppisApp/1.0 (${process.env.GEOCODER_CONTACT ?? "malinelundgren1991@gmail.com"})`,
"Accept": "application/json",
},
})
if (!r.ok) {
return res.status(r.status).json({ error: "Geocoding failed" })
}
const data = await r.json()
res.json(data)
} catch (e) {
console.error("Geocode proxy error:", e)
res.status(500).json({ error: "Upstream error" })
}
})

export default router
Loading