Chapter 05 (Invoice App Integrating with GraphQL server using Relay) - Intuit-London/imperial-react-workshop GitHub Wiki

Pre-Req

  1. https://github.com/Intuit-London/imperial-react-workshop/wiki/Chapter-03-(Invoice-App---Static-Data)
  2. https://github.com/Intuit-London/imperial-react-workshop/wiki/Chapter-04-(Understanding-GraphQL)

Installing Relay (continuation on the chapter03 project)

  1. npm install --save react-relay
  2. npm install --save-dev babel-relay-plugin
  3. npm install --save-dev babel-preset-stage-0
  4. npm install --save-dev babel-plugin-transform-class-properties

Setting up Babel-Relay plugin

  1. Download schema.json from Graphql server and copy it to build-utils/schema.json curl -X GET http://localhost:8080/introspection > /tmp/schema.json
  2. Create babelRelayPlugin.js under build-utils folder
var getbabelRelayPlugin = require('babel-relay-plugin');
var schema = require('./schema.json');
module.exports = getbabelRelayPlugin(schema.data);
  1. Update .babelrc file
{
  "presets": [
    "react",
    "es2015",
    "stage-0",
    {
      "plugins": ["./build-utils/babelRelayPlugin"]
    }
  ],
  "plugins":["transform-class-properties"]
}

Convert existing React Components to Relay Components

  1. Enhance InvoiceRow component as below
import Relay from "react-relay";
export default Relay.createContainer(InvoiceRow, {
  fragments: {
    invoice: () => Relay.QL`
      fragment on Invoice {
          id,
          number,
          creationDate,
          paid,
          totalAmount,
          customer {
            businessName
          }
      }`
  }
});
  1. Enhance InvoiceList component as below
import Relay from "react-relay";
export default Relay.createContainer(InvoiceList, {
  fragments: {
    invoices: () => Relay.QL`
      fragment on Invoice @relay(plural: true) {
          ${InvoiceRow.getFragment("invoice")}
      }`
  }
});
  1. Enhance InvoiceSummary component as below
import Relay from "react-relay";
  1. Enhance InvoiceCreate component as below
import Relay from "react-relay";
  1. Enhance InvoiceApp component as below
import Relay from "react-relay";
return (
        <div>
            <AppHeader createInvoice = {this.setCreateInvoice.bind(this)} listInvoice = {this.setListInvoice.bind(this)}/>
            <InvoiceSummary user={this.props.user}/>
            {this.state.isCreateInvoice ? <InvoiceCreate/> : <InvoiceList invoices={this.props.user.invoices}/> }
        </div>
      );
export default  Relay.createContainer(InvoiceApp, {
  fragments: {
    user: () => Relay.QL`
      fragment on User {
        firstName,
        invoices {
          ${InvoiceList.getFragment("invoices")}
        }
      }`
  }
});

Create InvoiceAppRenderer using Relay.Rendererin app folder

  1. Use Relay.Renderer to create our InvoiceAppRenderer.js
import React, {PropTypes} from "react";
import Relay from "react-relay";
import InvoiceRoute from "../routes/InvoiceRoute";
import InvoiceApp from "./InvoiceApp";

class InvoiceAppRenderer extends React.Component {

    constructor(props) {
        super(props);
        this.renderWidget = this.renderWidget.bind(this);
        Relay.injectNetworkLayer(
            new Relay.DefaultNetworkLayer('http://localhost:8080/graphql')
        );
    }

    renderWidget(data) {
        if (data.error) {
            return (<div>Error</div>);
        } else if (data.props) {
            return (<InvoiceApp user={data.props.user[0]}/>);
        }
        return (<div>Loading</div>)
    }

    render() {
        return (
            <Relay.Renderer
                Container={InvoiceApp}
                queryConfig={new InvoiceRoute()}
                environment={Relay.Store}
                render={this.renderWidget}
                forceFetch={true}
            />
        );
    }
}

export default InvoiceAppRenderer;
  1. Create InvoiceRoute.js under src/routes/
import Relay from "react-relay";

export default class InvoiceRoute extends Relay.Route {

    static routeName = "invoiceRoute";
    static queries = {
        user: () => Relay.QL `
          query {
            users (id: ["L1VzZXI6dXNlci0x"])
          }
        `
    };
}

Use the new InvoiceAppRenderer in index.js

  1. Imports
import InvoiceAppRenderer from './app/InvoiceAppRenderer';
  1. Remove dependency on the static json list. (Remove import invoiceList from './data/invoiceList)
  2. Change the InvoiceAppFactory to use InvoiceAppRenderer
var InvoiceAppFactory = React.createFactory(InvoiceAppRenderer);
  1. Build the project (npm run build)
  2. npm run dev
  3. Refresh your browser (http://localhost:8080) Ensure that the Graphql server is running at http://localhost:8080

Creation of Invoice

  1. Mutation for Create Invoice
import Relay from "react-relay";

export default class CreateInvoiceMutation extends Relay.Mutation {

    getMutation() {
        return Relay.QL `mutation createInvoice{createInvoice}`;
    }

    getVariables() {
        let data = {
          invoice: this.props
        };
        data.invoice.user = {"id" : "L1VzZXI6dXNlci0x"};
        return data;
    }

    getFatQuery() {
        return Relay.QL `
          fragment on User {
            invoices {
              number
            }
          }
          `;
    }

    getConfigs() {
        return [
              {
                type: "REQUIRED_CHILDREN",
                children: [Relay.QL `
                fragment on CreateInvoicePayload {
                  invoice {
                    user {
                      id
                    },
                    number,
                    totalAmount
                  }
                }
              `]
            }
            
        ];
    }

}
  1. Import CreateInvoiceMutation.js into InvoiceCreate component import CreateInvoiceMutation from '../mutations/CreateInvoiceMutation';

  2. Create function and associate with the button click.

  <button type="button" className="btn btn-primary" onClick={this.createInvoice.bind(this)}>Save</button> 
createInvoice = () => {
      const mutation = new CreateInvoiceMutation({
        number : this.invoiceNumber.value,
        creationDate : this.invoiceDate.value,
        paid : this.invoicePaid.checked,
        customer : {
          businessName: this.customername.value,
          id: "12431"
        },
        totalAmount: this.invoiceAmount.value
      });
      Relay.Store.commitUpdate(mutation, {onFailure: function() {
        alert('invoice creation failed');
      }, onSuccess: function() {
        alert('invoice created');
      }});
  }
⚠️ **GitHub.com Fallback** ⚠️