Netlify Dynamic Site Challenge: Make Your Favorite Image Collection 🎆
Tags: netlifychallenge, devchallenge, webdev, javascript
Published: 2024-05-13 01:46:30

*This is a submission for the [Netlify Dynamic Site Challenge](https://dev.to/challenges/netlify): Visual Feast.*


## What I Built
<!-- Share an overview about your project. -->
I have built a dynamic image gallery using [Pexels API](https://www.pexels.com/api/) and [Next.js](https://nextjs.org/). Landing page fetches a list of curated images from Pexels API. User can click on the image to view in detailed mode. User can also use the search functionality to find images of any topic. Moreover, authenticated users are allowed to like any image and create his/her own collection of liked images. From the user profile page, user can upload profile picture and change password.

## Demo
<!-- Share a link to your Netlify app and include some screenshots here. -->
You can find it here: [Photograph](https://photograph-mzd.netlify.app/).
Don't forget to register and create your favorite collection 🏞️ 🎑 🌄 🌃

### Gallery
![Gallery page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9vigl0w7dyzw659i7ga.png)

### Download in Desired Size

![Download image in your desired size](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otdcw0tagc60zluj1lzi.png)

### Collection of Liked Images

![Collection of liked images](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdib88rw2my01reuzi21.png)

### User Profile Page

![Profile page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8trf0n24fhi26gqz76ru.png)

### Upload Profile Picture

![Upload your profile picture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uve12wbgqicrmqnrw6pi.png)

## Platform Primitives
### Netlify Image CDN
<!-- Tell us how you leveraged the Netlify Image CDN. -->
I have leveraged [Netlify Image CDN](https://docs.netlify.com/image-cdn/overview/) to display and download optimized image. It is very easy to use and framework agnostic. You just need to send a request to `/.netlify/images` endpoint with query parameters specifying the source asset and desired transformation.

My `img` element for the gallery looks like below. `photo` is the resource from [Pexels API](https://www.pexels.com/api/documentation/#photos-overview).

```jsx
<img
  src={`/.netlify/images?url=${photo.src.original}&fit=cover&position=center&w=250`}
  alt={photo.alt}
  width={photo.width}
  height={photo.height}
  className="w-full h-full object-cover object-center"
  style={{ backgroundColor: photo.avg_color }}
/>
```

In the image details modal, I allow users to download the image in different sizes. Once again I leveraged Netlify Image CDN for resizing the image for downloading.

<!-- Did you implement additional platform primitives like Netlify Blobs or Cache Control? Tell us about that too! You may qualify for more than one prompt. -->

### Netlify Blobs
I have leveraged [Netlify Blobs](https://docs.netlify.com/blobs/overview/) for storing user data and profile picture.

Netlify encrypts blobs at rest and in transit. So, it is a secured storage for sensitive data.

When user resister on my site, I create and store a JSON document with the user account information in the Netlify Blobs. Moreover, you can also store metadata with your main data. I store account created timestamp and last password updated timestamp as metadata with the user account data.

Here is a sample code of how you can store user account information in Netlify Blobs.

```typescript
// user object
const newUser = {
  id,
  name,
  email,
  passwordHash,
};

// metadata, can be any arbitrary object.
const userMetadata = {
  createdAt: new Date().toISOString(),
  passwordUpdatedAt: new Date().toISOString(),
};

// getStore is imported from @netlify/blobs
const userStore = getStore("user");

// save data as JSON
await userStore.setJSON(id, newUser, { metadata: userMetadata });
```

Whenever user change the password, I update the `passwordUpdatedAt` metadata in the backend. That's how I can display last password updated at time in the profile page.

![Last password updated at](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vflspihxur62girmbelj.png)

I store users uploaded profile picture in the Netlify Blobs as [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).
```typescript
const profilePictureStore = getStore("profile-picture");

// save new profile picture
await profilePictureStore.set(randomId, arrayBuffer, {
  metadata: { fileName, type },
});
```

To access the uploaded image, I have created GET endpoint using Next.js API [route handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers). (BTW, it is also possible to access using [Netlify Functions](https://docs.netlify.com/functions/overview/)).

For example a GET request at `/api/profile-picture?imageId=your-image-id` endpoint reads the file from the Netlify Blobs and returns the raw file. To render the optimized profile picture, I again utilize Netlify Image CDN. A GET request to `/.netlify/images?url=/api/profile-picture?imageId=your-image-id&fit=cover&position=center&w=96` returns optimized image for my case.

The `img` tag for Avatar component is something like this:
```jsx
<img
  src={`/.netlify/images?url=${user.image}&fit=cover&position=center&w=96`}
  alt="avatar"
/>
```

One more thing I forgot to mention. When user like an image, that image data is stored with the user account data in the Netlify Blobs. That's how I keep track of the liked images of any user.

<!-- Team Submissions: Please pick one member to publish the submission and credit teammates by listing their DEV usernames directly in the body of the post. -->


<!-- Don't forget to add a cover image (if you want). -->


<!-- Thanks for participating! -->
## Conclusion
Code repository: [https://github.com/mazid1/photograph](https://github.com/mazid1/photograph)
That's all for today 🚀
I hope you enjoyed this article 🙌
Let me know your thoughts in the comment section 👇