Start Here: http://localhost:3000/team/7. (Redirects to first tab: http://localhost:3000/team/7/performance)
- presenters
- decorators
- rabl.json
- redux: actions, reducers, selectors
- reactRouter
Where profile tabs live:
- Performance
- Job Details
- Documents
- Personal Information
Example: The use of react-router-dom
for the tabs.
Why: []
import { Redirect, Route, Switch } from 'react-router-dom';`
const ROUTE_MAP = [
{ path: '/team/:userId/performance', RouteComponent: PerformanceView },
{ path: '/team/:userId/job_details', RouteComponent: JobDetailsView },
{ path: '/team/:userId/documents', RouteComponent: DocumentsView },
{
path: '/team/:userId/personal_information',
RouteComponent: PersonalInformationView,
},
];
<Switch>
<Route exact path={match.url}>
<Redirect to={`${match.url}/${defaultTab}`} />
</Route>
{ROUTE_MAP.map(({ path, RouteComponent }) => (
<Route exact key={path} path={path}>
<RouteComponent
user={user}
mobile={mobile}
getWidgetDefault={getWidgetDefault}
/>
</Route>
))}
</Switch>
Example: Uses arguments from redux, fetchTabData
being one of them.
How you can tell:
export default connect(
(state, props) => ({
stateOptions: sessionSelectors.getStateOptions(state, props),
}),
{
fetchTabData: employeeActions.fetchEmployeeTabData,
updateUserInfo: employeeActions.updateUserInfo,
}
)(PersonalInformationView);
- First argument of connect allows you to use the selectors and access them in your component.
- Second argument of connect allows you to use actions that you want to use in your component
import * as employeeActions from 'actions/employeeView';
fetchTabData
action within connect function
fetchTabData: employeeActions.fetchEmployeeTabData
client/src/actions/employeeView.js
export const fetchEmployeeTabData = (userId, tab, { force, reset } = {}) =>
reduxUtil.createAsyncGetAction(
`${routes.employeeRoute(userId)}/${tab}_tab`,
[
{ type: actionTypes.FETCH_EMPLOYEE_TAB_REQUEST, meta: { userId, tab } },
{
type: actionTypes.FETCH_EMPLOYEE_TAB_SUCCESS,
meta: { userId, tab, reset },
},
{ type: actionTypes.FETCH_EMPLOYEE_TAB_FAILURE, meta: { userId, tab } },
],
{
bailout: state =>
!force &&
(getIsEmployeeTabLoading(state, { id: userId, tab }) ||
getIsEmployeeTabLoaded(state, { id: userId, tab })),
}
);
How do reducers use actions? What's a reducer
client/src/reducers/employeeView.js
import { actionTypes } from 'actions/employeeView';
How are selectors used? What are selectors?
import * as sessionSelectors from 'selectors/session';
- controller for the personal information tab, empty but is needed
def personal_information_tab
# This is an api endpoint
# that is needed for the personal_information_tab.json.rabl "view"
end
- child
- glue
- nodes
- addditional attributes can be added via
app/decorators/user_decorator.rb
Passed to the PersonalInformationView/EmployeeInformationWidget/EmployeeInformationWidget.jsx
def has_jobs_at_more_than_one_company?(user)
user.all_companies.map(&:id).uniq.size > 1
end
Note: This was created 9/29/2021, there could have been changes to the following files
- presenter: app/presenters/employees_roster_presenter.rb
- rabl: app/views/team/employee_profile/personal_information_tab.json.rabl
- decorator: app/decorators/user_decorator.rb
- controller: app/controllers/team/employee_profile_controller.rb
- action: client/src/actions/employeeView.js
- reducer: client/src/reducers/employeeView.js
- child component: client/src/features/employeeProfile/PersonalInformationView/PersonalInformationView.jsx
- parent component: client/src/features/employeeProfile/PersonalInformationView/EmployeeInformationWidget/EmployeeInformationWidget.jsx
example of class component vs functional component in jsx:
passing in props at the top vs at the bottom file
class
in component nameAccountStatusCell.jsx (class) vs Header.jsx (functional)
Additionally:
Functional Component..
Additionally
reducers/entities
for shared reducers/ entities