Dwayne Harris 5 years ago
parent
commit
02aa30e0d1
  1. 1
      package.json
  2. 13
      src/actions/directory.ts
  3. 9
      src/actions/notifications.ts
  4. 24
      src/api/errors.ts
  5. 6
      src/components/app/app.scss
  6. 6
      src/components/app/app.tsx
  7. 5
      src/components/notification-container/notification-container.scss
  8. 3
      src/components/pages/directory/directory.scss
  9. 6
      src/components/pages/directory/index.ts
  10. 2
      src/components/pages/home/index.tsx
  11. 2
      src/components/pages/login/login.scss
  12. 10
      src/components/pages/register-group/index.ts
  13. 3
      src/components/user-info/user-info.scss
  14. 2
      src/components/user-info/user-info.tsx
  15. 2
      src/reducers/notifications.ts
  16. 7
      src/types/index.ts

1
package.json

@ -47,6 +47,7 @@
"@fortawesome/free-solid-svg-icons": "^5.10.2",
"@fortawesome/react-fontawesome": "^0.1.4",
"classnames": "^2.2.6",
"history": "^4.9.0",
"lodash": "^4.17.15",
"normalizr": "^3.4.1",
"react": "^16.9.0",

13
src/actions/directory.ts

@ -1,12 +1,11 @@
import { Action, AnyAction } from 'redux'
import { ThunkAction, ThunkDispatch } from 'redux-thunk'
import { Action } from 'redux'
import { normalize } from 'normalizr'
import { getGroup, getGroups } from '../api/groups'
import { setEntity, setEntities } from '../actions/entities'
import { startRequest, finishRequest } from '../actions/requests'
import { groupSchema } from '../store/schemas'
import { AppState } from '../types'
import { AppThunkAction } from '../types'
const FETCH_GROUP_ID = 'FETCH_GROUP'
const FETCH_GROUPS_ID = 'FETCH_GROUPS'
@ -43,8 +42,8 @@ export const setContinuation = (continuation: string): SetContinuationAction =>
payload: continuation,
})
export const fetchGroup = (id: string): ThunkAction<Promise<void>, AppState, void, AnyAction> => {
return async (dispatch: ThunkDispatch<AppState, void, AnyAction>) => {
export const fetchGroup = (id: string): AppThunkAction => {
return async dispatch => {
dispatch(startRequest(FETCH_GROUP_ID))
try {
@ -58,8 +57,8 @@ export const fetchGroup = (id: string): ThunkAction<Promise<void>, AppState, voi
}
}
export const fetchGroups = (sort?: string, continuation?: string): ThunkAction<Promise<void>, AppState, void, AnyAction> => {
return async (dispatch: ThunkDispatch<AppState, void, AnyAction>) => {
export const fetchGroups = (sort?: string, continuation?: string): AppThunkAction => {
return async dispatch => {
dispatch(startRequest(FETCH_GROUPS_ID))
try {

9
src/actions/notifications.ts

@ -1,8 +1,7 @@
import { Action, AnyAction } from 'redux'
import { ThunkAction, ThunkDispatch } from 'redux-thunk'
import { Action } from 'redux'
import { v1 } from 'uuid'
import { AppState, NotificationType } from '../types'
import { AppThunkAction, NotificationType } from '../types'
export interface AddNotificationAction extends Action {
type: 'NOTIFICATIONS_ADD_NOTIFICATION'
@ -54,8 +53,8 @@ export const setNotificationAuto = (id: string): SetNotificationAutoAction => ({
payload: id,
})
export const showNotification = (type: NotificationType, content: string, expiration: number = 5000): ThunkAction<Promise<void>, AppState, void, AnyAction> => {
return async (dispatch: ThunkDispatch<AppState, void, AnyAction>) => {
export const showNotification = (type: NotificationType, content: string, expiration: number = 5000): AppThunkAction => {
return async dispatch => {
const id = v1()
dispatch(addNotification(id, type, content))

24
src/api/errors.ts

@ -1,4 +1,26 @@
import { FormNotification } from '../types'
import { History } from 'history'
import { showNotification } from 'src/actions/notifications'
import { AppThunkDispatch, FormNotification } from 'src/types'
export function handleApiError(err: HttpError, dispatch: AppThunkDispatch, history: History) {
if (err instanceof ServerError) {
dispatch(showNotification('error', 'Server Error'))
}
if (err instanceof BadRequestError) {
dispatch(showNotification('error', `Error: ${err.message}`))
}
if (err instanceof UnauthorizedError) {
dispatch(showNotification('error', 'You need to be logged in.'))
history.push('/login')
}
if (err instanceof NotFoundError) {
dispatch(showNotification('error', 'Not found.'))
}
}
export class HttpError extends Error {
statusCode: number

6
src/components/app/app.scss

@ -8,7 +8,13 @@ $primary: $primary-color;
@import "../../../node_modules/bulma/sass/utilities/_all.sass";
@import "../../../node_modules/bulma/sass/base/_all.sass";
@import "../../../node_modules/bulma/sass/form/_all.sass";
@import "../../../node_modules/bulma/sass/grid/columns.sass";
@import "../../../node_modules/bulma/sass/elements/button.sass";
@import "../../../node_modules/bulma/sass/elements/notification.sass";
@import "../../../node_modules/bulma/sass/elements/other.sass";
@import "../../../node_modules/bulma/sass/elements/title.sass";
@import "../../../node_modules/bulma/sass/components/media.sass";
$main-menu-padding: 1rem;
$main-column-padding: $main-menu-padding;

6
src/components/app/app.tsx

@ -16,6 +16,8 @@ interface Props {
fetching: boolean
}
const Divider: FC = () => <>&nbsp;&nbsp;&#9900;&nbsp;&nbsp;</>
const App: FC<Props> = ({ menuCollapsed, fetching }) => {
const mainMenuWidth = 300
const mainColumnLeftMargin = menuCollapsed ? 0 : mainMenuWidth
@ -42,7 +44,9 @@ const App: FC<Props> = ({ menuCollapsed, fetching }) => {
<footer>
<div className="content has-text-centered has-text-white is-size-7">
<Link className="has-text-white is-inline-block" to="/">Home</Link>
&nbsp;&nbsp;&#9900;&nbsp;&nbsp;
<Divider />
<Link className="has-text-white is-inline-block" to="/">Developers</Link>
<Divider />
<Link className="has-text-white is-inline-block" to="/">About</Link>
<p>&copy; 2019 Flexor.cc</p>

5
src/components/notification-container/notification-container.scss

@ -1,8 +1,3 @@
@import "../../../node_modules/bulma/sass/utilities/_all.sass";
@import "../../../node_modules/bulma/sass/base/_all.sass";
@import "../../../node_modules/bulma/sass/elements/button.sass";
@import "../../../node_modules/bulma/sass/elements/notification.sass";
div#notification-container {
bottom: 10px;
position: absolute;

3
src/components/pages/directory/directory.scss

@ -1,3 +0,0 @@
@import "../../../../node_modules/bulma/sass/utilities/_all.sass";
@import "../../../../node_modules/bulma/sass/base/_all.sass";
@import "../../../../node_modules/bulma/sass/elements/title.sass";

6
src/components/pages/directory/index.ts

@ -1,10 +1,8 @@
import { connect } from 'react-redux'
import { ThunkDispatch } from 'redux-thunk'
import { AnyAction } from 'redux'
import { fetchGroups } from 'src/actions/directory'
import { getDirectoryGroups } from 'src/selectors'
import { AppState } from 'src/types'
import { AppState, AppThunkDispatch } from 'src/types'
import Directory from './directory'
@ -12,7 +10,7 @@ const mapStateToProps = (state: AppState) => ({
groups: getDirectoryGroups(state),
})
const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, void, AnyAction>) => ({
const mapDispatchToProps = (dispatch: AppThunkDispatch) => ({
fetchGroups: () => {
dispatch(fetchGroups())
},

2
src/components/pages/home/index.tsx

@ -2,7 +2,7 @@ import React, { FC } from 'react'
const Home: FC = () => (
<div>
<h1>Home</h1>
<h1 className="title">Home</h1>
</div>
)

2
src/components/pages/login/login.scss

@ -1,2 +0,0 @@
@import "../../../../node_modules/bulma/sass/utilities/_all.sass";
@import "../../../../node_modules/bulma/sass/form/_all.sass";

10
src/components/pages/register-group/index.ts

@ -1,10 +1,9 @@
import { AnyAction } from 'redux'
import { ThunkDispatch } from 'redux-thunk'
import { connect } from 'react-redux'
import { handleApiError } from 'src/api/errors'
import { fetchGroup } from 'src/actions/directory'
import { getEntity } from 'src/selectors'
import { AppState } from 'src/types'
import { AppState, AppThunkDispatch } from 'src/types'
import RegisterGroup, { Props } from './register-group'
@ -12,13 +11,12 @@ const mapStateToProps = (state: AppState, ownProps: Props) => ({
group: getEntity(state, 'group', ownProps.match.params.id),
})
const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, void, AnyAction>, ownProps: Props) => ({
const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({
fetchGroup: async () => {
try {
await dispatch(fetchGroup(ownProps.match.params.id))
} catch (err) {
console.error('Expected error')
console.error(err)
handleApiError(err, dispatch, ownProps.history)
}
},
})

3
src/components/user-info/user-info.scss

@ -1,6 +1,3 @@
@import "../../../node_modules/bulma/sass/utilities/_all.sass";
@import "../../../node_modules/bulma/sass/components/media.sass";
$image-size: 64px;
div.empty-image {

2
src/components/user-info/user-info.tsx

@ -32,7 +32,7 @@ const UserInfo: FC<Props> = ({ authenticated, user }) => {
<p>
<Link to="/login" className="is-size-5 has-text-white has-text-weight-bold">Log In</Link>
<br />
<Link to="/communities" className="is-size-7 has-text-primary">Register</Link>
<Link to="/communities" className="is-size-7 has-text-light">Register</Link>
</p>
</div>
</div>

2
src/reducers/notifications.ts

@ -11,13 +11,13 @@ const reducer: Reducer<NotificationsState, NotificationActions> = (state = initi
const { id, type, content } = action.payload
return [
...state,
{
id,
type,
content,
auto: true,
},
...state,
]
case 'NOTIFICATIONS_REMOVE_NOTIFICATION':
return state.filter(notification => notification.id !== action.payload)

7
src/types/index.ts

@ -1,3 +1,7 @@
import { AnyAction } from 'redux'
import { ThunkDispatch, ThunkAction } from 'redux-thunk'
import { AppState } from './store'
export type FetchMethods = 'get' | 'post' | 'put'
export interface FetchOptions {
@ -32,3 +36,6 @@ export {
EntitiesState,
AppState,
} from './store'
export type AppThunkDispatch = ThunkDispatch<AppState, void, AnyAction>
export type AppThunkAction = ThunkAction<Promise<void>, AppState, void, AnyAction>
Loading…
Cancel
Save