|
| 1 | +const Apollo = require('apollo-client'); |
| 2 | +const fetch = require('isomorphic-fetch'); // eslint-disable-line no-unused-vars |
| 3 | +const gql = require('graphql-tag'); |
| 4 | + |
| 5 | +module.exports = w => { |
| 6 | + const enableEvents = typeof window !== 'undefined'; // only enable events if we are in the browser |
| 7 | + const initialRoute = w.location.pathname.replace(w.document.querySelector('base').getAttribute('href'), '').replace('/',''); |
| 8 | + const routes = [ |
| 9 | + {route:'agriculture', title:'Agriculture'}, |
| 10 | + {route:'food', title:'Food'}, |
| 11 | + {route:'retail', title:'Retail'} |
| 12 | + ]; |
| 13 | + const sectors = { |
| 14 | + 'agriculture': 1, |
| 15 | + 'food': 12, |
| 16 | + 'retail': 7 |
| 17 | + }; |
| 18 | + |
| 19 | + const client = new Apollo.ApolloClient({ |
| 20 | + networkInterface: Apollo.createNetworkInterface({ |
| 21 | + uri: 'https://api.kivaws.org/graphql' |
| 22 | + }) |
| 23 | + }); |
| 24 | + |
| 25 | + // get loan data from the graphql endpoint |
| 26 | + const query = sector => client.query({ |
| 27 | + query: gql`{ |
| 28 | + loans(limit: 3, filters: { |
| 29 | + sector: ${sector} |
| 30 | + }) { |
| 31 | + values { name, use, image { url(presetSize: loan_default) } } |
| 32 | + } |
| 33 | + }` |
| 34 | + }); |
| 35 | + |
| 36 | + // attach dom event handlers after render |
| 37 | + const onRender = () => { |
| 38 | + // navigate on the client when links are clicked |
| 39 | + w.document.querySelectorAll('a').forEach(element => { |
| 40 | + element.addEventListener('click', event => { |
| 41 | + event.preventDefault(); |
| 42 | + const route = event.target.getAttribute('href'); |
| 43 | + w.history.pushState(route, `view:${route}`, route); |
| 44 | + render({route, loans:[]}); |
| 45 | + query(sectors[route]).then(result => { |
| 46 | + render({ |
| 47 | + route, |
| 48 | + loans: result.data && result.data.loans && result.data.loans.values || [] |
| 49 | + }); |
| 50 | + }) |
| 51 | + }); |
| 52 | + }); |
| 53 | + }; |
| 54 | + |
| 55 | + // render to the dom using context ctx |
| 56 | + const render = ctx => { |
| 57 | + const existingRoot = w.document.getElementById('root'); |
| 58 | + const newRoot = w.document.createElement('div'); |
| 59 | + newRoot.id = 'root'; |
| 60 | + |
| 61 | + newRoot.innerHTML = ` |
| 62 | + ${routes.reduce((html, {route,title}) => `${html} |
| 63 | + ${route === ctx.route ? ` |
| 64 | + <span>${title}</span> |
| 65 | + ` : ` |
| 66 | + <a href="${route}">${title}</a> |
| 67 | + `} |
| 68 | + `,'')} |
| 69 | + <ul> |
| 70 | + ${ctx.loans.reduce((html, loan) => `${html} |
| 71 | + <li> |
| 72 | + <img src="${loan.image.url}" alt="Picture of ${loan.name}"> |
| 73 | + <h2>${loan.name}</h2> |
| 74 | + </li> |
| 75 | + `,'')} |
| 76 | + </ul> |
| 77 | + `; |
| 78 | + |
| 79 | + if(existingRoot) { |
| 80 | + w.document.body.replaceChild(newRoot, existingRoot); |
| 81 | + } |
| 82 | + else { |
| 83 | + w.document.body.insertBefore(newRoot, w.document.body.firstChild); |
| 84 | + } |
| 85 | + |
| 86 | + if(enableEvents) { |
| 87 | + onRender(); |
| 88 | + } |
| 89 | + }; |
| 90 | + |
| 91 | + // attach browser navigation event handler |
| 92 | + if(enableEvents) { |
| 93 | + // update page if back/forward used |
| 94 | + w.addEventListener('popstate', event => { |
| 95 | + render({route: event.state}); |
| 96 | + }); |
| 97 | + } |
| 98 | + |
| 99 | + // initial fetch/render |
| 100 | + return new Promise((resolve, reject) => { |
| 101 | + if(sectors[initialRoute] === undefined) { |
| 102 | + render({ |
| 103 | + route: initialRoute, |
| 104 | + loans: [] |
| 105 | + }); |
| 106 | + resolve(); |
| 107 | + } |
| 108 | + else { |
| 109 | + query(sectors[initialRoute]).then(result => { |
| 110 | + render({ |
| 111 | + route: initialRoute, |
| 112 | + loans: result.data && result.data.loans && result.data.loans.values || [] |
| 113 | + }); |
| 114 | + resolve(); |
| 115 | + }).catch(err => reject(err)); |
| 116 | + } |
| 117 | + }); |
| 118 | +} |
0 commit comments