diff --git a/superglue/lib/action_creators/requests.js b/superglue/lib/action_creators/requests.js index b459d430..e9143a3b 100644 --- a/superglue/lib/action_creators/requests.js +++ b/superglue/lib/action_creators/requests.js @@ -8,7 +8,6 @@ import { removePropsAt, } from '../utils' import { - CLEAR_FLASH, BEFORE_FETCH, BEFORE_VISIT, BEFORE_REMOTE, @@ -66,15 +65,6 @@ function buildMeta(pageKey, page, state) { } } -export function clearFlash({ pageKey }) { - return { - type: CLEAR_FLASH, - payload: { - pageKey, - }, - } -} - export function remote( path, { @@ -95,8 +85,9 @@ export function remote( body, }) pageKey = pageKey || getState().superglue.currentPageKey + const currentPageKey = getState().superglue.currentPageKey - dispatch(beforeRemote({ fetchArgs })) + dispatch(beforeRemote({ currentPageKey, fetchArgs })) dispatch(beforeFetch({ fetchArgs })) return fetch(...fetchArgs) @@ -142,9 +133,6 @@ export function visit( let pageKey = urlToPageKey(path) return (dispatch, getState) => { - const currentKey = getState().superglue.currentPageKey - dispatch(clearFlash({ pageKey: currentKey })) - placeholderKey = placeholderKey && urlToPageKey(placeholderKey) const hasPlaceholder = !!getState().pages[placeholderKey] @@ -175,7 +163,8 @@ export function visit( signal, }) - dispatch(beforeVisit({ fetchArgs })) + const currentPageKey = getState().superglue.currentPageKey + dispatch(beforeVisit({ currentPageKey, fetchArgs })) dispatch(beforeFetch({ fetchArgs })) lastVisitController.abort() diff --git a/superglue/lib/actions.js b/superglue/lib/actions.js index fa4b22b5..525f1cd1 100644 --- a/superglue/lib/actions.js +++ b/superglue/lib/actions.js @@ -4,7 +4,6 @@ export const BEFORE_REMOTE = '@@superglue/BEFORE_REMOTE' export const SAVE_RESPONSE = '@@superglue/SAVE_RESPONSE' export const HANDLE_GRAFT = '@@superglue/HANDLE_GRAFT' -export const CLEAR_FLASH = '@@superglue/CLEAR_FLASH' export const SUPERGLUE_ERROR = '@@superglue/ERROR' export const GRAFTING_ERROR = '@@superglue/GRAFTING_ERROR' diff --git a/superglue/lib/index.js b/superglue/lib/index.js index bfca6fd0..bae238f7 100644 --- a/superglue/lib/index.js +++ b/superglue/lib/index.js @@ -27,6 +27,7 @@ export { REMOVE_PAGE, GRAFTING_ERROR, GRAFTING_SUCCESS, + HISTORY_CHANGE, } from './actions' export { @@ -46,8 +47,11 @@ export { getIn } from './utils/immutability' export { urlToPageKey } function pageToInitialState(key, page) { + const slices = page.slices || {} + return { pages: { [key]: page }, + ...slices, } } diff --git a/superglue/lib/reducers/index.js b/superglue/lib/reducers/index.js index 860a4cc6..a2a518c5 100644 --- a/superglue/lib/reducers/index.js +++ b/superglue/lib/reducers/index.js @@ -1,7 +1,6 @@ import { setIn, getIn, urlToPageKey } from '../utils' import { REMOVE_PAGE, - CLEAR_FLASH, SAVE_RESPONSE, HANDLE_GRAFT, HISTORY_CHANGE, @@ -96,15 +95,6 @@ export function appendReceivedFragmentsOntoPage( return nextState } -export function addFlash(state, pageKey, receivedFlash) { - const nextState = { ...state } - const nextPage = { ...state[pageKey] } - nextPage.flash = { ...nextPage.flash, ...receivedFlash } - nextState[pageKey] = nextPage - - return nextState -} - export function graftNodeOntoPage(state, pageKey, node, pathToNode) { if (!node) { console.warn( @@ -132,7 +122,6 @@ export function handleGraft(state, pageKey, page) { data: receivedNode, path: pathToNode, fragments: receivedFragments = [], - flash: receivedFlash, } = page return [ @@ -144,7 +133,6 @@ export function handleGraft(state, pageKey, page) { pageKey, receivedFragments ), - (nextState) => addFlash(nextState, pageKey, receivedFlash), ].reduce((memo, fn) => fn(memo), state) } @@ -185,16 +173,6 @@ export function pageReducer(state = {}, action) { return nextState } - case CLEAR_FLASH: { - const { pageKey } = action.payload - const nextState = { ...state } - const nextPage = { ...state[pageKey] } - - nextPage.flash = {} - nextState[pageKey] = nextPage - - return nextState - } case COPY_PAGE: { const nextState = { ...state } const { from, to } = action.payload diff --git a/superglue/lib/utils/react.js b/superglue/lib/utils/react.js index f747de8b..7c061cd3 100644 --- a/superglue/lib/utils/react.js +++ b/superglue/lib/utils/react.js @@ -14,12 +14,11 @@ export function mapStateToProps( let params = ownProps const csrfToken = state.superglue.csrfToken pageKey = urlToPageKey(pageKey) - const { data, flash, fragments } = state.pages[pageKey] || { + const { data, fragments } = state.pages[pageKey] || { data: {}, - flash: {}, fragments: [], } - return { ...data, ...params, pageKey, csrfToken, flash, fragments } + return { ...data, ...params, pageKey, csrfToken, fragments } } export const mapDispatchToProps = { diff --git a/superglue/spec/features/navigation.spec.js b/superglue/spec/features/navigation.spec.js index 7d0ca846..1f87c358 100644 --- a/superglue/spec/features/navigation.spec.js +++ b/superglue/spec/features/navigation.spec.js @@ -71,7 +71,6 @@ describe('start', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -106,7 +105,6 @@ describe('start', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -137,7 +135,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -165,7 +162,6 @@ describe('navigation', () => { const pageState = { data: { heading: 'Some heading 2' }, - flash: {}, csrfToken: 'token', assets: ['application-123.js', 'application-123.js'], componentIdentifier: 'about', @@ -194,7 +190,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -230,7 +225,6 @@ describe('navigation', () => { const pageState = { data: { heading: 'Some heading 2' }, - flash: {}, csrfToken: 'token', assets: ['application-123.js', 'application-123.js'], componentIdentifier: 'about', @@ -272,7 +266,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -315,7 +308,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -369,7 +361,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -419,7 +410,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -496,7 +486,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -540,7 +529,6 @@ describe('navigation', () => { data: { heading: 'this is page 1', }, - flash: {}, componentIdentifier: 'home', assets: ['123.js', '123.css'], fragments: [], @@ -561,7 +549,6 @@ describe('navigation', () => { const pageState = { data: { heading: 'Some heading 2' }, - flash: {}, csrfToken: 'token', assets: ['application-123.js', 'application-123.js'], componentIdentifier: 'about', @@ -591,7 +578,6 @@ describe('navigation', () => { heading: 'this is page 1', address: undefined, }, - flash: {}, fragments: [], componentIdentifier: 'home', } diff --git a/superglue/spec/fixtures.js b/superglue/spec/fixtures.js index 1911b76a..5832d471 100644 --- a/superglue/spec/fixtures.js +++ b/superglue/spec/fixtures.js @@ -5,7 +5,6 @@ export const visitSuccess = () => { csrfToken: 'token', assets: ['application-123.js', 'application-123.js'], componentIdentifier: 'about', - flash: {}, fragments: [], }), headers: { @@ -23,7 +22,6 @@ export const graftSuccessWithNewZip = () => { path: 'data.address', csrfToken: 'token', assets: ['application-new123.js', 'application-new123.js'], - flash: {}, fragments: [], }), headers: { diff --git a/superglue/spec/lib/action_creators.spec.js b/superglue/spec/lib/action_creators.spec.js index 7f21edd3..6cac93d9 100644 --- a/superglue/spec/lib/action_creators.spec.js +++ b/superglue/spec/lib/action_creators.spec.js @@ -272,6 +272,7 @@ describe('action creators', () => { { type: '@@superglue/BEFORE_REMOTE', payload: { + currentPageKey: "/bar", fetchArgs: [ '/foo?props_at=data.body&__=0', { @@ -327,6 +328,7 @@ describe('action creators', () => { { type: '@@superglue/BEFORE_REMOTE', payload: { + currentPageKey: "/bar", fetchArgs: [ '/foo?props_at=data.body.aside.top&__=0', { @@ -780,7 +782,7 @@ describe('action creators', () => { const expectedActions = [ { type: '@@superglue/BEFORE_REMOTE', - payload: { fetchArgs: ['/foo?__=0', expect.any(Object)] }, + payload: { currentPageKey: "/bar", fetchArgs: ['/foo?__=0', expect.any(Object)] }, }, { type: '@@superglue/BEFORE_FETCH', @@ -856,7 +858,7 @@ describe('action creators', () => { const expectedActions = [ { type: '@@superglue/BEFORE_REMOTE', - payload: { fetchArgs: ['/foo?__=0', expect.any(Object)] }, + payload: { currentPageKey: '/bar', fetchArgs: ['/foo?__=0', expect.any(Object)] }, }, { type: '@@superglue/BEFORE_FETCH', @@ -987,7 +989,7 @@ describe('action creators', () => { const expectedActions = [ { type: '@@superglue/BEFORE_REMOTE', - payload: { fetchArgs: ['/foo?__=0', expect.any(Object)] }, + payload: { currentPageKey: "/bar", fetchArgs: ['/foo?__=0', expect.any(Object)] }, }, { type: '@@superglue/BEFORE_FETCH', @@ -1021,7 +1023,7 @@ describe('action creators', () => { const expectedActions = [ { type: '@@superglue/BEFORE_REMOTE', - payload: { fetchArgs: ['/foo?__=0', expect.any(Object)] }, + payload: { currentPageKey: "/bar", fetchArgs: ['/foo?__=0', expect.any(Object)] }, }, { type: '@@superglue/BEFORE_FETCH', @@ -1060,7 +1062,7 @@ describe('action creators', () => { const expectedActions = [ { type: '@@superglue/BEFORE_REMOTE', - payload: { fetchArgs: ['/foo?__=0', expect.any(Object)] }, + payload: { currentPageKey: "/bar", fetchArgs: ['/foo?__=0', expect.any(Object)] }, }, { type: '@@superglue/BEFORE_FETCH', @@ -1316,7 +1318,6 @@ describe('action creators', () => { data: { address: {}, }, - flash: {}, csrfToken: 'token', assets: [ 'application-new123.js', @@ -1333,10 +1334,6 @@ describe('action creators', () => { fetchMock.mock('/details?props_at=data.address&__=0', mockResponse) const expectedActions = [ - { - type: '@@superglue/CLEAR_FLASH', - payload: { pageKey: '/current' }, - }, { type: '@@superglue/COPY_PAGE', payload: { from: '/current', to: '/details' }, diff --git a/superglue/spec/lib/reducers.spec.js b/superglue/spec/lib/reducers.spec.js index 90ea785f..8f204f1b 100644 --- a/superglue/spec/lib/reducers.spec.js +++ b/superglue/spec/lib/reducers.spec.js @@ -83,7 +83,6 @@ describe('reducers', () => { a: { b: { c: {} } }, }, fragments: [], - flash: {}, }, } @@ -97,7 +96,6 @@ describe('reducers', () => { path: 'data.a.b.c', }, ], - flash: {}, } const nextState = pageReducer(prevState, { @@ -120,7 +118,6 @@ describe('reducers', () => { path: 'data.a.b.c', }, ], - flash: {}, }, }) }) @@ -138,7 +135,6 @@ describe('reducers', () => { path: 'data.a.b.c', }, ], - flash: {}, }, } const receivedPage = { @@ -151,7 +147,6 @@ describe('reducers', () => { path: 'data.a.b.c', }, ], - flash: {}, } const nextState = pageReducer(prevState, { @@ -174,7 +169,6 @@ describe('reducers', () => { path: 'data.a.b.c', }, ], - flash: {}, }, }) }) @@ -189,7 +183,6 @@ describe('reducers', () => { d: { e: { f: {} } }, }, fragments: [], - flash: {}, }, } @@ -203,7 +196,6 @@ describe('reducers', () => { path: 'data.d.e.f', }, ], - flash: {}, } const nextState = pageReducer(prevState, { @@ -227,7 +219,6 @@ describe('reducers', () => { path: 'data.d.e.f', }, ], - flash: {}, }, }) }) @@ -246,7 +237,6 @@ describe('reducers', () => { path: 'data.d.e.f', }, ], - flash: {}, }, } @@ -254,7 +244,6 @@ describe('reducers', () => { data: {}, path: 'data.a.b.c', fragments: [], - flash: {}, } const nextState = pageReducer(prevState, { @@ -275,13 +264,11 @@ describe('reducers', () => { '/foo': { data: { a: { b: { c: {} } } }, fragments: [], - flash: {}, }, } const receivedPage = { data: { foo: 1 }, fragments: [], - flash: {}, } const pageKey = '/foo' @@ -301,7 +288,6 @@ describe('reducers', () => { '/foo': { data: { a: { b: { c: {} } } }, fragments: [], - flash: {}, }, } @@ -309,7 +295,6 @@ describe('reducers', () => { data: { foo: 1 }, path: 'data.a.b.c', fragments: [], - flash: {}, } const nextState = pageReducer(prevState, { @@ -324,7 +309,6 @@ describe('reducers', () => { '/foo': { data: { a: { b: { c: { foo: 1 } } } }, fragments: [], - flash: {}, }, }) }) @@ -359,13 +343,11 @@ describe('reducers', () => { '/foo': { data: { a: { b: { c: {} } } }, fragments: [], - flash: {}, }, } const receivedPage = { path: 'data.a.b.c', - flash: {}, } const nextState = pageReducer(prevState, { diff --git a/superglue/spec/lib/utils/react.spec.js b/superglue/spec/lib/utils/react.spec.js index 001bd774..196b04c6 100644 --- a/superglue/spec/lib/utils/react.spec.js +++ b/superglue/spec/lib/utils/react.spec.js @@ -6,7 +6,6 @@ describe('mapStateToToProps', () => { pages: { '/foo': { data: { heading: 'hi' }, - flash: {}, }, }, superglue: { @@ -19,7 +18,6 @@ describe('mapStateToToProps', () => { heading: 'hi', pageKey: '/foo', csrfToken: 'token123', - flash: {}, }) }) }) diff --git a/superglue_rails/lib/generators/rails/templates/edit.json.props b/superglue_rails/lib/generators/rails/templates/edit.json.props index 6173407f..455957d4 100644 --- a/superglue_rails/lib/generators/rails/templates/edit.json.props +++ b/superglue_rails/lib/generators/rails/templates/edit.json.props @@ -1,10 +1,8 @@ if @post.errors.any? - content = { + json.errors({ explanation: "#{pluralize(@<%= singular_table_name %>.errors.count, "error")} prohibited this post from being saved:", messages: @<%= singular_table_name %>.errors.full_messages.map{|msg| {body: msg}} - } - - flash.now[:form_error] = content + }) end json.form(partial: 'form') do diff --git a/superglue_rails/lib/generators/rails/templates/new.json.props b/superglue_rails/lib/generators/rails/templates/new.json.props index 6cd98c5c..4fe6e0b3 100644 --- a/superglue_rails/lib/generators/rails/templates/new.json.props +++ b/superglue_rails/lib/generators/rails/templates/new.json.props @@ -1,10 +1,8 @@ if @post.errors.any? - content = { + json.errors({ explanation: "#{pluralize(@<%= singular_table_name %>.errors.count, "error")} prohibited this post from being saved:", messages: @<%= singular_table_name %>.errors.full_messages.map{|msg| {body: msg}} - } - - flash.now[:form_error] = content + }) end json.form(partial: 'form') do diff --git a/superglue_rails/lib/generators/rails/templates/web/edit.js b/superglue_rails/lib/generators/rails/templates/web/edit.js index 048a114c..f06e944a 100644 --- a/superglue_rails/lib/generators/rails/templates/web/edit.js +++ b/superglue_rails/lib/generators/rails/templates/web/edit.js @@ -1,17 +1,14 @@ import React from 'react' -// import * as actionCreators from 'javascript/packs/action_creators' -// import {useDispatch} from 'react-redux' +// import { useSelector } from 'react-redux' export default function <%= plural_table_name.camelize %>Edit ({ // visit, // remote, form, - flash, + error, <%= singular_table_name.camelize(:lower) %>Path, <%= plural_table_name.camelize(:lower) %>Path, }) { - const error = flash.form_error - const messagesEl = error && (

{ error.explanation }

diff --git a/superglue_rails/lib/generators/rails/templates/web/index.js b/superglue_rails/lib/generators/rails/templates/web/index.js index 4962171a..ddf5762f 100644 --- a/superglue_rails/lib/generators/rails/templates/web/index.js +++ b/superglue_rails/lib/generators/rails/templates/web/index.js @@ -1,14 +1,14 @@ import React from 'react' -// import * as actionCreators from 'javascript/packs/action_creators' -// import {useDispatch} from 'react-redux' +import { useSelector } from 'react-redux' export default function <%= plural_table_name.camelize %>Index({ // visit, // remote, - flash, new<%= singular_table_name.camelize %>Path, <%= plural_table_name.camelize(:lower) %> = [], }) { + const flash = useSelector((state) => state.flash) + const <%= singular_table_name.camelize(:lower) %>Items = <%= plural_table_name.camelize(:lower) %>.map((<%= singular_table_name.camelize(:lower) %>, key) => { const deleteForm = <%=singular_table_name.camelize(:lower)%>.deleteForm; @@ -31,7 +31,7 @@ export default function <%= plural_table_name.camelize %>Index({ return (
-

{flash.notice}

+

{flash && flash.notice}

<%= plural_table_name.capitalize %>

diff --git a/superglue_rails/lib/generators/rails/templates/web/new.js b/superglue_rails/lib/generators/rails/templates/web/new.js index d0cbb3c4..0356c713 100644 --- a/superglue_rails/lib/generators/rails/templates/web/new.js +++ b/superglue_rails/lib/generators/rails/templates/web/new.js @@ -1,16 +1,13 @@ import React from 'react' -// import * as actionCreators from 'javascript/packs/action_creators' -// import { useDispatch } from 'react-redux' +// import { useSelector } from 'react-redux' export default function <%= plural_table_name.camelize %>New({ // visit, // remote form, - flash, + error, <%= plural_table_name.camelize(:lower) %>Path, }) { - const error = flash.form_error - const messagesEl = error && (

{ error.explanation }

diff --git a/superglue_rails/lib/generators/rails/templates/web/show.js b/superglue_rails/lib/generators/rails/templates/web/show.js index 2f3061cd..9226da86 100644 --- a/superglue_rails/lib/generators/rails/templates/web/show.js +++ b/superglue_rails/lib/generators/rails/templates/web/show.js @@ -1,17 +1,17 @@ import React from 'react' -// import * as actionCreators from 'javascript/packs/action_creators' -// import {useDispatch} from 'react-redux' +import { useSelector } from 'react-redux' export default function <%= plural_table_name.camelize %>Show({ // visit, // remote, - flash, <%- attributes_list_with_timestamps.select{|attr| attr != :id }.each do |attr| -%> <%=attr.camelize(:lower)%>, <%- end -%> edit<%= singular_table_name.camelize %>Path, <%= plural_table_name.camelize(:lower) %>Path }) { + const flash = useSelector((state) => state.flash) + return (

{flash && flash.notice}

diff --git a/superglue_rails/lib/install/templates/web/action_creators.js b/superglue_rails/lib/install/templates/web/action_creators.js deleted file mode 100644 index 323a233a..00000000 --- a/superglue_rails/lib/install/templates/web/action_creators.js +++ /dev/null @@ -1,14 +0,0 @@ -// Example: -// -// import { -// CLEAR_FORM_ERRORS -// } from './actions' -// -// export function clearFormErrors(pageKey) { -// return { -// type: CLEAR_FORM_ERRORS, -// payload: { -// pageKey, -// } -// } -// } diff --git a/superglue_rails/lib/install/templates/web/actions.js b/superglue_rails/lib/install/templates/web/actions.js index 422e6a90..aff6aa1d 100644 --- a/superglue_rails/lib/install/templates/web/actions.js +++ b/superglue_rails/lib/install/templates/web/actions.js @@ -1,3 +1,6 @@ -// Example: -// -// export const CLEAR_FORM_ERRORS = 'CLEAR_FORM_ERRORS' +import { createAction } from '@reduxjs/toolkit' +import { SAVE_RESPONSE, BEFORE_VISIT, UPDATE_FRAGMENTS } from '@thoughtbot/superglue' + +export const saveResponse = createAction(SAVE_RESPONSE) +export const beforeVisit = createAction(BEFORE_VISIT) +export const updateFragments = createAction(UPDATE_FRAGMENTS) diff --git a/superglue_rails/lib/install/templates/web/application.js b/superglue_rails/lib/install/templates/web/application.js index 6ee07bb2..fbfb90ae 100644 --- a/superglue_rails/lib/install/templates/web/application.js +++ b/superglue_rails/lib/install/templates/web/application.js @@ -1,13 +1,11 @@ import React from 'react'; -import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; -import reduceReducers from 'reduce-reducers'; import thunk from 'redux-thunk'; import { Provider } from 'react-redux'; -import { render } from 'react-dom'; -import { ApplicationBase, fragmentMiddleware } from '@thoughtbot/superglue'; -import { applicationRootReducer, applicationPagesReducer } from './reducer'; +import { createRoot } from 'react-dom/client'; +import { ApplicationBase } from '@thoughtbot/superglue'; import { buildVisitAndRemote } from './application_visit'; import { pageIdentifierToPageComponent } from './page_to_page_mapping'; +import { buildStore } from './store' class Application extends ApplicationBase { mapping() { @@ -18,27 +16,8 @@ class Application extends ApplicationBase { return buildVisitAndRemote(navRef, store); } - buildStore(initialState, { superglue: superglueReducer, pages: pagesReducer }) { - // Create the store - // See `./reducer.js` for an explaination of the two included reducers - const composeEnhancers = - (this.hasWindow && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || - compose; - const reducer = reduceReducers( - combineReducers({ - superglue: superglueReducer, - pages: reduceReducers(pagesReducer, applicationPagesReducer), - }), - applicationRootReducer - ); - - const store = createStore( - reducer, - initialState, - composeEnhancers(applyMiddleware(thunk, fragmentMiddleware)) - ); - - return store; + buildStore(initialState, { superglue, pages}) { + return buildStore(initialState, superglue, pages); } } @@ -48,7 +27,8 @@ if (typeof window !== "undefined") { const location = window.location; if (appEl) { - render( + const root = createRoot(appEl); + root.render( , - appEl + /> ); } }); } + diff --git a/superglue_rails/lib/install/templates/web/application.json.props b/superglue_rails/lib/install/templates/web/application.json.props index 45ef105e..22442dc1 100644 --- a/superglue_rails/lib/install/templates/web/application.json.props +++ b/superglue_rails/lib/install/templates/web/application.json.props @@ -21,4 +21,7 @@ end json.restore_strategy 'fromCacheAndRevisitInBackground' json.rendered_at Time.now.to_i -json.flash flash.to_h + +json.slices do + json.flash flash.to_h +end diff --git a/superglue_rails/lib/install/templates/web/flash.js b/superglue_rails/lib/install/templates/web/flash.js new file mode 100644 index 00000000..465d388b --- /dev/null +++ b/superglue_rails/lib/install/templates/web/flash.js @@ -0,0 +1,19 @@ +import { createSlice } from '@reduxjs/toolkit' +import { saveResponse, beforeVisit } from '../actions' + +export const flashSlice = createSlice({ + name: 'flash', + initialState: {}, + extraReducers: (builder) => { + builder.addCase(beforeVisit, (state, action) => { + return {} + }) + builder.addCase(saveResponse, (state, action) => { + const { page } = action.payload; + + return { + ...state, ...page.slices.flash + } + }) + } +}) diff --git a/superglue_rails/lib/install/templates/web/pages.js b/superglue_rails/lib/install/templates/web/pages.js new file mode 100644 index 00000000..81a092fe --- /dev/null +++ b/superglue_rails/lib/install/templates/web/pages.js @@ -0,0 +1,15 @@ +import { createSlice } from '@reduxjs/toolkit' +import { saveResponse, beforeVisit } from '../actions' + +export const pagesSlice = createSlice({ + name: 'pages', + // extraReducers: (builder) => { + // builder.addCase(beforeVisit, (state, action) => { + // const {currentPageKey} = action.payload + // + // const currentPage = draft[currentPageKey] + // delete currentPage.error + // }) + // } +}) + diff --git a/superglue_rails/lib/install/templates/web/reducer.js b/superglue_rails/lib/install/templates/web/reducer.js deleted file mode 100644 index 092e1698..00000000 --- a/superglue_rails/lib/install/templates/web/reducer.js +++ /dev/null @@ -1,44 +0,0 @@ -// Example: -// -// import { -// CLEAR_FORM_ERRORS -// } from './actions' -// import produce from "immer" -// -// export const applicationPagesReducer = (state = {}, action) => { -// switch(action.type) { -// case CLEAR_FORM_ERRORS: { -// const {pageKey} = action.payload -// -// return produce(state, draft => { -// const currentPage = draft[pageKey] -// delete currentPage.errors -// }) -// } -// default: -// return state -// } -// } - - -// The applicationPageReducer is for cross page reducers -// Its common to add to this. You'll typically have to pass a pageKey to the -// action payload to distinguish the current page -// -// The pageKey is passed through the props in your component. Access it like -// this: `this.props.pageKey` then dispatch it in an action -export const applicationPagesReducer = (state = {}, action) => { - switch(action.type) { - default: - return state - } -} - -// The applicationRootReducer is for app wide reducers -// Its rare to be adding to this. -export const applicationRootReducer = (state = {}, action) => { - switch(action.type) { - default: - return state - } -} diff --git a/superglue_rails/lib/install/templates/web/store.js b/superglue_rails/lib/install/templates/web/store.js new file mode 100644 index 00000000..91ea8f72 --- /dev/null +++ b/superglue_rails/lib/install/templates/web/store.js @@ -0,0 +1,32 @@ +import { configureStore } from '@reduxjs/toolkit' +import { pagesSlice } from "./slices/pages" +import { flashSlice } from "./slices/flash" +import { + BEFORE_VISIT, + BEFORE_FETCH, + BEFORE_REMOTE, + fragmentMiddleware +} from '@thoughtbot/superglue' + +export const buildStore = (initialState, superglueReducer, supergluePagesReducer) => { + + return configureStore({ + preloadedState: initialState, + devTools: process.env.NODE_ENV !== 'production', + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [BEFORE_VISIT, BEFORE_FETCH, BEFORE_REMOTE], + }, + }).concat(fragmentMiddleware), + reducer: { + superglue: superglueReducer, + pages: (state, action) => { + const nextState = supergluePagesReducer(state, action) + return pagesSlice.reducer(nextState, action) + }, + flash: flashSlice.reducer + }, + }); +}; + diff --git a/superglue_rails/lib/install/web.rb b/superglue_rails/lib/install/web.rb index b13ffecf..f6325542 100644 --- a/superglue_rails/lib/install/web.rb +++ b/superglue_rails/lib/install/web.rb @@ -22,11 +22,14 @@ def app_js_path say "Copying page_to_page_mapping.js file to #{app_js_path}" copy_file "#{__dir__}/templates/web/page_to_page_mapping.js", "#{app_js_path}/page_to_page_mapping.js" -say "Copying reducer.js file to #{app_js_path}" -copy_file "#{__dir__}/templates/web/reducer.js", "#{app_js_path}/reducer.js" +say "Copying flash.js file to #{app_js_path}" +copy_file "#{__dir__}/templates/web/flash.js", "#{app_js_path}/slices/flash.js" -say "Copying action_creators.js file to #{app_js_path}" -copy_file "#{__dir__}/templates/web/action_creators.js", "#{app_js_path}/action_creators.js" +say "Copying pages.js file to #{app_js_path}" +copy_file "#{__dir__}/templates/web/pages.js", "#{app_js_path}/slices/pages.js" + +say "Copying store.js file to #{app_js_path}" +copy_file "#{__dir__}/templates/web/store.js", "#{app_js_path}/store.js" say "Copying actions.js file to #{app_js_path}" copy_file "#{__dir__}/templates/web/actions.js", "#{app_js_path}/actions.js" @@ -46,7 +49,7 @@ def app_js_path say "Installing FormProps" run "bundle add form_props" -say "Installing React, Redux, and Superglue" -run "yarn add history react-redux redux-thunk redux reduce-reducers immer @thoughtbot/superglue --save" +say "Installing Superglue and friends" +run "yarn add history react react-dom @reduxjs/toolkit react-redux @thoughtbot/superglue --save" say "Superglue is Installed! 🎉", :green diff --git a/superglue_rails/lib/tasks/install.rake b/superglue_rails/lib/tasks/install.rake index 591df58a..089c94c6 100644 --- a/superglue_rails/lib/tasks/install.rake +++ b/superglue_rails/lib/tasks/install.rake @@ -1,17 +1,7 @@ namespace :superglue do - desc "Verifies if any version of react is in package.json" - task :verify_react do - package_json = JSON.parse(File.read(Rails.root.join("package.json"))) - - if package_json["dependencies"]["react"].nil? - warn "React not installed. Did you install React? https://github.com/rails/webpacker#react" - warn "Exiting!" && exit! - end - end - namespace :install do desc "Install everything needed for superglue web" - task "web" => ["superglue:verify_react"] do + task "web" do template = File.expand_path("../install/web.rb", __dir__) exec "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{template}" end diff --git a/superglue_rails/test/acceptance/superglue_installation_acceptance.rb b/superglue_rails/test/acceptance/superglue_installation_acceptance.rb index f80a11e7..abbbffcf 100644 --- a/superglue_rails/test/acceptance/superglue_installation_acceptance.rb +++ b/superglue_rails/test/acceptance/superglue_installation_acceptance.rb @@ -9,6 +9,9 @@ SUPERGLUE_RAILS_PATH = File.join(ROOT_DIR, "superglue_rails") SUPERGLUE_SUPERGLUE_PATH = File.join(ROOT_DIR, "superglue") VERSION = File.read(File.expand_path("../../../VERSION", __dir__)).strip +SUPERGLUE_JS_VERSION = JSON.parse( + File.read(File.expand_path("../../../superglue/package.json", __dir__)).strip +)["version"] SERVER_PORT = "3000" @@ -52,7 +55,7 @@ def successfully(command, silent = false) def update_package_json content = File.read("package.json").gsub( /"@thoughtbot\/superglue.*$/, - "\"@thoughtbot/superglue\":\"file:#{SUPERGLUE_SUPERGLUE_PATH}/thoughtbot-superglue-#{VERSION}.tgz\"," + "\"@thoughtbot/superglue\":\"file:#{SUPERGLUE_SUPERGLUE_PATH}/thoughtbot-superglue-#{SUPERGLUE_JS_VERSION}.tgz\"," ) File.open("package.json", "w") { |file| file.puts content } end