diff --git a/.env.example b/.env.example index ab599c4..e9cfdd5 100644 --- a/.env.example +++ b/.env.example @@ -14,3 +14,7 @@ GOOGLE_AUTH_CALLBACK_URL= # debugging SIMULATE_USER_ID=0 + +# tapontap - optional +# TAPONTAP_INSTANCE=http://localhost:5000 +# AUTH_TOKEN=foobarqux diff --git a/TODO.md b/TODO.md index bb54646..acc58dd 100644 --- a/TODO.md +++ b/TODO.md @@ -1,14 +1,27 @@ # todo +## TapOnTap integration + +- Remove the extra button press in the registration flow +- Delete Cheers +- Cleanup classname inconsistency in the CardRegister steps components + + + ## bugs, issues - there's no 404 page +- probably need to ping the /whoami endpoint every x minutes to ensure you're still logged in + - currently cached in the store forever, even after your session dies. ## new features, improvements +- Redirect to last URL on login +- ladda + - also a component for the button + confirm UI pattern - Link to the Keg Detail from the Keg List view? - - UI needs to be more helpful distinguishing/explaining Kegs vs Beers +- UI needs to be more helpful distinguishing/explaining Kegs vs Beers - Searchable ModelSelect - Inline 'Add Brewery' from the Add Beer view - Brewery list should be searchable diff --git a/client/src/actions/card-register.js b/client/src/actions/card-register.js new file mode 100644 index 0000000..782892f --- /dev/null +++ b/client/src/actions/card-register.js @@ -0,0 +1,69 @@ +/** + * CardRegister Actions. + + */ + +import dispatcher from '../dispatcher'; +import { fetcher } from './util'; + + +// reset the store to intial values +export function reset() { + dispatcher.dispatch({ + type: 'CARD_REGISTER_RESET', + }); +} + +// Transition to a different step +export function stepTo(step) { + dispatcher.dispatch({ + type: 'CARD_REGISTER_STEP_TO', + step, + }); +} + +// retry with a different token +export function retry() { + dispatcher.dispatch({ + type: 'CARD_REGISTER_RETRY', + }); +} + +// fetch card uid from TapOnTap +export function fetchCard() { + dispatcher.dispatch({ + type: 'REQUEST_FETCH_CARD', + }); + + return fetcher('/api/v1/cards/register') + .then(({ cardUid }) => dispatcher.dispatch({ + type: 'RECEIVE_FETCH_CARD', + cardUid, + })) + .catch(error => dispatcher.dispatch({ + type: 'RECEIVE_FETCH_CARD', + error, + })); +} + +// register the card to the current user +export function registerCard(uid) { + dispatcher.dispatch({ + type: 'REQUEST_REGISTER_CARD', + }); + + return fetcher('/api/v1/cards/register', { + method: 'POST', + body: JSON.stringify({ + uid, + }), + }) + .then(data => dispatcher.dispatch({ + type: 'RECEIVE_REGISTER_CARD', + data, + })) + .catch(error => dispatcher.dispatch({ + type: 'RECEIVE_REGISTER_CARD', + error, + })); +} diff --git a/client/src/actions/cards.js b/client/src/actions/cards.js new file mode 100644 index 0000000..7cb74ca --- /dev/null +++ b/client/src/actions/cards.js @@ -0,0 +1,35 @@ +/** + * Card Actions + */ + +import dispatcher from '../dispatcher'; +import { fetcher } from './util'; +import { addNotification } from './notifications'; + + +// delete a card +export function deleteCard(id) { // eslint-disable-line import/prefer-default-export + dispatcher.dispatch({ + type: 'REQUEST_DELETE_CARD', + id, + }); + + return fetcher(`/api/v1/cards/${id}`, { + method: 'DELETE', + }) + .then(() => { + dispatcher.dispatch({ + type: 'RECEIVE_DELETE_CARD', + id, + }); + addNotification('Removed your NFC Token.'); + }) + .catch((error) => { + dispatcher.dispatch({ + type: 'RECEIVE_DELETE_CARD', + error, + }); + + throw error; // rethrow for action caller + }); +} diff --git a/client/src/actions/kegs.js b/client/src/actions/kegs.js index dea903f..27da23a 100644 --- a/client/src/actions/kegs.js +++ b/client/src/actions/kegs.js @@ -29,6 +29,28 @@ export function fetchKegs() { }); } +// fetch the kegs to get the cheerses. +// same as fetchKegs() but doesn't dispatch +// REQUEST_FETCH_KEGS so you can't see it happening. +// polling this will update the cheerses on the +// keg list view in real time (ish). +// todo - websockets! +export function fetchCheers() { + dispatcher.dispatch({ + type: 'REQUEST_FETCH_KEGS_CHEERS', + }); + + return fetcher('/api/v1/kegs') + .then(data => dispatcher.dispatch({ + type: 'RECEIVE_FETCH_KEGS_CHEERS', + data, + })) + .catch(error => dispatcher.dispatch({ + type: 'RECEIVE_FETCH_KEGS_CHEERS', + error, + })); +} + // fetch one keg export function fetchKeg(id) { dispatcher.dispatch({ diff --git a/client/src/actions/profile.js b/client/src/actions/profile.js index 6d21e88..96ad3cc 100644 --- a/client/src/actions/profile.js +++ b/client/src/actions/profile.js @@ -24,19 +24,20 @@ export function fetchProfile() { })); } -// fetch the Cheers for our profile. -export function fetchProfileCheers() { +// fetch the extra data for the profile view; +// Cheers, Cards. +export function fetchProfileFull() { dispatcher.dispatch({ - type: 'REQUEST_FETCH_PROFILE_CHEERS', + type: 'REQUEST_FETCH_PROFILE_FULL', }); - return fetcher('/api/v1/profile/cheers') + return fetcher('/api/v1/profile/full') .then(data => dispatcher.dispatch({ - type: 'RECEIVE_FETCH_PROFILE_CHEERS', + type: 'RECEIVE_FETCH_PROFILE_FULL', data, })) .catch(error => dispatcher.dispatch({ - type: 'RECEIVE_FETCH_PROFILE_CHEERS', + type: 'RECEIVE_FETCH_PROFILE_FULL', error, })); } diff --git a/client/src/components/app/index.js b/client/src/components/app/index.js index 63ec7e7..27cf81e 100644 --- a/client/src/components/app/index.js +++ b/client/src/components/app/index.js @@ -40,6 +40,12 @@ class AppComponent extends React.Component { }); } + hideMenu() { + this.setState({ + showMenu: false, + }); + } + render() { const { props } = this; const isAdmin = props.profile && props.profile.data.admin; @@ -66,7 +72,7 @@ class AppComponent extends React.Component { >☰ -