Have ideas to improve npm?Join in the discussion! »

    @advancedalgos/web-components

    0.0.18 • Public • Published

    Advanced Algos Web Components

    npm version

    Introduction

    The is a repository for shared React web components between the Advanced Algos platform modules.

    Installation

    This is a Node.js module available through the npm registry. Installation is done using the npm install command:

    $ npm install @advancedalgos/web-components

    Usage

    MessageCard

    The Message Card is a simple component for outputting a message within a card. Great for using as a placeholder or adding simple formatting to error and loading messages.

    import React from 'react'
    import { MessageCard } from '@advancedalgos/web-components'
     
    export const YourComponent = () => (
      <div>
        <MessageCard message='A message!' />
        <MessageCard message='That can also wrap other components' >
          <div className='loader'>Loading...</div>
        </MessageCard>
      </div>
    )

    Message Card Configuration Options

    Props Type Default Note
    message String --- Display any string
    <children> Node --- Can accept children nodes.

    Image Upload

    Image Upload is a complex multi-functional component that encompasses allowing a user to preview an existing image, choose a new image, crop and resize that image, and then upload that image to Azure Blob Storage.

    We use an Azure Shared Access Signature (SAS) created on a by-container basis that should be created on your server-side. The ImageUpload component then appends the SAS query parameters to the Storage Blob url with container and filename to upload the image.

    View the Full Example for examples with use of client-side GraphQL mutation and server-side generation of the SASurl.

    import React from 'react'
    import { MessageCard, ImageUpload } from '@advancedalgos/web-components'
     
    const YourComponent = ({ handleAvatar, filename, containerName, avatar, AzureStorageUrl, AzureSASURL }) => (
      <React.Fragment>
        <h1>Upload an image</h1>
        <ImageUpload
          handleUrl={handleAvatar}
          fileName={fileName}
          containerName={containerName}
          existingImage={avatar}
          imagePreviewConfig={{ width: 350, height:'auto', title: 'Change Avatar', fontSize: '1.5em' }}
          cropContainerConfig={{ x: 10, y: 10, width: 200, height: 200 }}
          cropPreviewBox={{ width: 350, height: 350 }}
          saveImageConfig={{
            quality: 0.6,
            maxWidth: 200,
            maxHeight: 200,
            autoRotate: true,
            mimeType: 'image/jpeg'
          }}
          containerStyle={{
            display: 'block',
            margin: '30px',
            height: '100px',
            width: '400px',
            overflow: 'visible'
          }}
          dropzoneStyle={{ height: 200 }}
          AzureStorageUrl={AzureStorageUrl}
          AzureSASURL={AzureSASURL}
          cropRatio={1}
        />
      </React.Fragment>
    )
     
    export default YourComponent

    Image Upload Configuration Options

    Props Type Note
    handleUrl Function Required. Receives the url of the uploaded image
    fileName String Required. File name that image is uploaded to storage as
    containerName String Required. StorageContainer name that image is uploaded to
    existingImage String (url) Url of pre-existing image. Usually will be same as URL returned from handleUrl
    imagePreviewConfig Object Existing image preview and change button text
    containerStyle Object Style of main container
    dropzoneStyle Object Style of dropzone container
    cropContainerConfig Object Size and location of cropper on image in crop mode
    cropPreviewBox Object Dimensions of cropper preview
    cropRatio Number ratio (width/height) image is cropped at eg. 1/1, 4/1, 16/9, 800/150
    saveImageConfig Object Configuration of image saved to storage
    AzureStorageUrl String Required. Azure Storage Url (just the storage url; container and filename will be appended)
    AzureSASURL String Required. The Azure Shared Access Signature (SAS) that allows saving to the Blob without using full-access keys. See Full Example for server side example.

    Image Upload Default Values

    Props Default
    containerStyle { display: 'block', margin: 0, height: 200, width: 200, overflow: 'visible' }
    dropzoneStyle { height: 200 }
    imagePreviewConfig { width: 350, height: auto, title: 'Change Avatar', fontSize: '24px' }
    cropContainerConfig { x: 10, y: 10, width: 200, height: 200 }
    cropPreviewBox { width: 350, height: 350 }
    cropRatio 1 / 1
    saveImageConfig {quality: 0.6, maxWidth: 200, maxHeight: 200, autoRotate: true, debug: true, mimeType: 'image/jpeg}

    Image Upload Full Example

    YourComponent.js

    import React, { Component } from 'react'
    import gql from 'graphql-tag'
    import { MessageCard, ImageUpload } from '@advancedalgos/web-components'
     
    const GET_AZURE_SAS = gql`
      mutation getAzureSAS($containerName: String!) {
        getAzureSAS(containerName: $containerName)
      }
    `
     
    export class YourComponent extends Component {
      constructor (props) {
        super(props)
     
        this.handleAvatar = this.handleAvatar.bind(this)
     
        this.state = {
          avatar: null
        }
      }
     
      render () {
        const { user, avatar } = this.props
        return (
          <Mutation mutation={UPDATE_USER_PROFILE} >
            {(updateUserProfile, { loading, error, data }) => {
             let user = data.updateUserProfile
                if (loading) {
                  loader = (<MessageCard message='Updating user profile...' />)
                }
     
              return (
                  <Mutation mutation={GET_AZURE_SAS} >
                    {(getAzureSAS, { loading, error, data }) => {
     
                      const AzureStorageUrl = process.env.AZURE_STORAGE_URL
                      const containerName = user.name
                      const fileName = `${user.name}-avatar.jpg`
                      let avatar = user.profile.avatar
     
                      let AzureSASURL
                      if (!loading && data !== undefined) {
                        AzureSASURL = data.getAzureSAS
                      } else {
                        getAzureSAS({ variables: { containerName: containerName } })
                      }
     
                      if (loading || data === undefined) {
                        return (<MessageCard message='Loading...' />)
                      } else {
                        return (
                          <React.Fragment>
                            <ImageUpload
                              handleUrl={this.handleAvatar}
                              fileName={fileName}
                              containerName={containerName}
                              existingImage={avatar}
                              imagePreviewConfig={{ width: 350, title: 'Change Avatar' }}
             cropContainerConfig={{ x: 10, y: 10, width: 200, height: 200 }}                          cropPreviewBox={{ width: 350, height: 350 }}
                              saveImageConfig={{
                                quality: 0.6,
                                maxWidth: 200,
                                maxHeight: 200,
                                autoRotate: true,
                                mimeType: 'image/jpeg'
                              }}
                              AzureStorageUrl={AzureStorageUrl}
                              AzureSASURL={AzureSASURL}
                              cropRatio={1}
                            />
                          </React.Fragment>
                        )
                      }
                    }}
                  </Mutation>      
         )
            }}
          </Mutation>
        )
      }
     
      handleAvatar (avatarUrl) {
        console.log('handleAvatar: ', avatarUrl)
        this.setState({ avatar: `${avatarUrl}?${Math.random()}` })  // random number makes browser load latest image version
      }
    }

    ServerSide: server.js

    const { createSASQueryURL } = require('./storage/azure')
     
    ...
    const resolvers = {
        ...
        Mutation: {
            async getAzureSAS(parent, { teamSlug }, ctx, info) {
              const SASUrl = createSASQueryURL(teamSlug)
              console.log('createSASQueryURL: ', SASUrl)
              return SASUrl
            }
        }
    }
     

    ServerSide: azure.js

    const Azure = require("@azure/storage-blob")
    const azureAccount = process.env.AZURE_STORAGE_ACCOUNT
    const azureKey = process.env.AZURE_STORAGE_ACCESS_KEY
    const azureStorageUrl = process.env.AZURE_STORAGE_URL
     
    const createSASQueryURL = async (containerName) => {
      let today = new Date()
      let week = new Date()
      week.setDate(today.getDate() + 7)
     
      // Create SharedKeyCredential and attach to pipline
      const SKC = new Azure.SharedKeyCredential(azureAccount, azureKey)
      const pipeline = Azure.StorageURL.newPipeline(SKC)
     
      // Create container URL
      const serviceURL = new Azure.ServiceURL(azureStorageUrl, pipeline)
      const containerURL = Azure.ContainerURL.fromServiceURL(serviceURL, containerName)
     
      //list container and check if already exists.
      let marker
      let containerCheck = null
      do {
        const listContainersResponse = await serviceURL.listContainersSegment(
          Azure.Aborter.None,
          marker,
        )
        marker = listContainersResponse.marker;
        for (const container of listContainersResponse.containerItems) {
     
          if(container.name === containerName){
            containerCheck = container.name
          }
        }
      } while (marker)
     
      // if container doesn't exist, create one
      let newContainer
      if(containerCheck === null){
        newContainer = await containerURL.create(Azure.Aborter.None, { access: 'blob' })
      }
     
      // Set permissions for service, resource types and containers
      const SASContainerPerms = await Azure.AccountSASPermissions.parse('rwlacu')
      const SASServicePerms = await Azure.AccountSASServices.parse('b')
      const SASResourceTypes = await Azure.AccountSASResourceTypes.parse('co')
     
      // Generate SAS url
      const SASQueryParameters = await Azure.generateBlobSASQueryParameters(
        {
          version: '2017-11-09',
          protocol: 'https,http',
          expiryTime: week,
          permissions: 'rwlac',
          containerName: containerName
        }, SKC )
     
      return SASQueryParameters
    }
     
    module.exports = { createSASQueryURL }
     
     

    Page

    The Page component is a wrapper that uses React Helmet to inject page title, description and other metadata into the header to represent the current view.

    Supports basic meta data as well as metadata for Twitter and Facebook

    ** Note 1:** View .env.sample for extra configuration variables that should be added to your environment variables.

    ** Note 2:** Uses react-router-dom withRouter HoC and requires being used with & components

    import React from 'react'
    import { Page, MessageCard } from '@advancedalgos/web-components'
     
    export const YourComponent = () => (
      <Page
        title='Advanced Algos Development Platform'
        subtitile='A Platform View'
        description='This describes the current view of the Advanced Algos Development Platform'
      >
        <MessageCard message={text('Message', 'This message is wrapped by a page component. Check header source to see inserted metadata.')} />
      </Page>
    )

    Page Configuration Options

    Props Type Default Note
    title String --- Title of site
    subtitle String --- Title of current view
    description String --- Description of current view
    twitter String --- Twitter handle (eg. @advancedalgos) and enables Twitter card metadata
    facebook Boolean --- Enables Facebook OpenGraph metadata
    image string --- URL of image that represents current view
    <children> Node --- Can accept children nodes.

    Developing This Package

    ==================================

    Libraries

    Getting Started

    $ npm install
    $ npm run storybook

    Testing

    $ npm run test

    Install

    npm i @advancedalgos/web-components

    DownloadsWeekly Downloads

    5

    Version

    0.0.18

    License

    SEE LICENSE IN LICENSE

    Unpacked Size

    58.9 kB

    Total Files

    20

    Last publish

    Collaborators

    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar