Showing posts from March, 2019

43. Media Library - Postmortem and What's Next

To wrap up our series on the media-library project I want to reflect on the positive and negative parts of the project with a view to doing things better in the future, and then discuss what features might make sense for the next iteration. Positive Hooks - This entire application is written without using a single React Class Component. To say I am a fan of Hooks is an understatement. By not using Hooks I find my code is both easier to write and read. Render props - I am a fan of the render props pattern, although it does seem that custom Hooks may replace render props over time. I am not a fan of Higher Order Components (HOC). This entire application is written without creating a single HOC (but we do use a few). Firebase (the platform) - I really like Firebase as a platform. I don't remember having a problem with it throughout the entire development cycle. I appreciate the efforts to keep Firebase minimal and not bloat it with a bunch of rarely used features. In particular,

42. Media Library - Publish

It feels like this blog series has been going on forever, maybe because it has. We finally reached our goal of having something worth showing users in the last post. We can now turn our attention to getting the application published somewhere users can access it. Code Background  Not surprisingly we will leverage Firebase Hosting to host our application. This in one of the most straightforward operations related to our application.  Walk Through I am going to start by creating a production build of our application. > npm run build There are some good bits in the create-react-app documentation about installing and using serve. This is a good way to test your production build before you push it to a live server. See: . The steps to deploy to Firebase Hosting are also discussed on that same page. Below are the steps we are using and the answers to the Fir

41. Media Library - Images for Users

In this post we will finally get to the key part of the application - letting users select and download images. Code Background  For the most part this post is about pulling together a lot of the concepts we have applied elsewhere.  Walk Through Let's start by replacing our Images component placeholder with a component that will display all of the images for a selected property. Before we create the component itself I want to create a helper component. I want to be able to let users filter the list of displayed images. We can use react-select to help. I'm going to create a generic component that uses react-select to allow us to generically identify a list for filtering. MultiSettingSelect.jsx import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import Select from 'react-select'; export default function MultiSettingSelect({   values,  

40. Media Library - Property, with map, for Users

In the last post we created a property list from which users can select a property. In this post we continue by creating the property components/pages. Code Background  There is one new concept I want to introduce in this post. When we display property details I want to display a map with the location of the property. I've decided to use Leaflet, and the React helper library React-Leaflet. In my opinion Leaflet is the best open-source option for displaying the map we want.   Walk Through Let's start by create the property container to pull in the bits of the store we will need. We want a specific property, its images and the settings. Notice that we are using ownProps to leverage the property ID from the url to filter on a specific property. PropertyContainer.jsx import { connect } from 'react-redux'; import Property from '../../

39. Media Library - Properties for Users

We have done quite a lot of work to this point but we have yet to reach our most critical milestone - when we can turn over the application to a standard user to try the application and give us feedback. In this post we will finally start to add some GUI for the User (as opposed to the Admin, for whom we've added quite a bit of functionality). Code Background  There are no new concepts in this post. We will be working primarily on something I refer to as the Users side of the application. When I say that, I'm attempting to distinguish between how a standard user will use the application as opposed to an admin user. We will be focusing on the Properties component/page which has been a placeholder up to this point. We'll be following a lot of the same patterns we developed when creating the Admin side of the application. Walk Through We already have a Properties component, but it doesn't do anything

AWS Amplify - Overriding auto-generated resolver logic

It has been about a month since AWS announced a number of really important enhancements to AWS Amplify ( ). Several of the enhancements are important to me and I want to highlight one of them. Before We Start In order to take advantage of these new features you need to be running a new version of the AWS Amplify CLI (the steps to upgrade are dead simple and are covered in the AWS post above). Be warned that if you haven't updated for a while things can break after you upgrade - DO NOT DO THIS IN PRODUCTION. If you do upgrade, you will be prompted to migrate your project, and quite a few changes will be made to your project. I had not updated my Amplify CLI for a while and I ran into an issue with the new(ish) max-depth attribute you can set on your API. You can easily adjust the max-depth per:

38. Media Library - Accommodate new image data

We have spent the past several posts working with Firebase Functions, in part to enhance images. We have added additional metadata and we are generating additional image sizes. In this post we can start to account for these changes. Code Background  We are not introducing any new concepts in this post. We will continue to evolve what we have previously created. Walk Through Now that we are generating new "small" and "thumb" versions of an image I want to be sure to delete them if a user deletes the image. actions/images.js (updates) ... // delete file(s) from storage     await deleteFile(,;     if (image.repros.thumbnail) {       await deleteFile(, `thumb_${}`);     }     if (image.repros.small) {       await deleteFile(, `small_${}`);     } ... Similarly, we are generating additional metadata for each image. I