Dwayne Harris
5 years ago
13 changed files with 234 additions and 52 deletions
-
50src/actions/directory.ts
-
4src/api/errors.ts
-
39src/components/group-logs/group-logs.tsx
-
26src/components/group-logs/index.tsx
-
35src/components/member-list/index.tsx
-
25src/components/member-list/member-list.tsx
-
58src/components/pages/group-admin/group-admin.tsx
-
14src/components/pages/group-admin/index.ts
-
11src/components/pages/loading/index.tsx
-
6src/selectors/directory.ts
-
9src/store/schemas.ts
-
7src/types/entities.ts
-
2src/types/store.ts
@ -0,0 +1,39 @@ |
|||||
|
import React, { FC, useEffect } from 'react' |
||||
|
import noop from 'lodash/noop' |
||||
|
import moment from 'moment' |
||||
|
import { GroupLog } from 'src/types' |
||||
|
|
||||
|
export interface Props { |
||||
|
group: string |
||||
|
logs?: GroupLog[] |
||||
|
fetchLogs?: () => void |
||||
|
} |
||||
|
|
||||
|
const MemberList: FC<Props> = ({ group, logs = [], fetchLogs = noop }) => { |
||||
|
useEffect(() => { |
||||
|
if (logs.length === 0) fetchLogs() |
||||
|
}, [group]) |
||||
|
|
||||
|
return ( |
||||
|
<table className="table"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Who</th> |
||||
|
<th>What</th> |
||||
|
<th>When</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{logs.map(log => ( |
||||
|
<tr> |
||||
|
<td>{log.user.id}</td> |
||||
|
<td>{log.content}</td> |
||||
|
<td>{moment(log.created).format('MMMM Do YYYY, h:mm:ss a')}</td> |
||||
|
</tr> |
||||
|
))} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
export default MemberList |
@ -0,0 +1,26 @@ |
|||||
|
import { connect } from 'react-redux' |
||||
|
import { handleApiError } from 'src/api/errors' |
||||
|
import { fetchLogs } from 'src/actions/directory' |
||||
|
import { getLogs } from 'src/selectors/directory' |
||||
|
import { AppState, AppThunkDispatch } from 'src/types' |
||||
|
|
||||
|
import GroupLogs, { Props } from './group-logs' |
||||
|
|
||||
|
const mapStateToProps = (state: AppState) => ({ |
||||
|
logs: getLogs(state), |
||||
|
}) |
||||
|
|
||||
|
const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({ |
||||
|
fetchLogs: () => { |
||||
|
try { |
||||
|
dispatch(fetchLogs(ownProps.group)) |
||||
|
} catch (err) { |
||||
|
handleApiError(err, dispatch) |
||||
|
} |
||||
|
}, |
||||
|
}) |
||||
|
|
||||
|
export default connect( |
||||
|
mapStateToProps, |
||||
|
mapDispatchToProps |
||||
|
)(GroupLogs) |
@ -1,17 +1,26 @@ |
|||||
import React, { FC } from 'react' |
|
||||
|
import { connect } from 'react-redux' |
||||
|
import { handleApiError } from 'src/api/errors' |
||||
|
import { fetchGroupMembers } from 'src/actions/directory' |
||||
|
import { getGroupMembers } from 'src/selectors/directory' |
||||
|
import { AppState, AppThunkDispatch } from 'src/types' |
||||
|
|
||||
import { User } from 'src/types' |
|
||||
|
import MemberList, { Props } from './member-list' |
||||
|
|
||||
import MemberListItem from './member-list-item' |
|
||||
|
const mapStateToProps = (state: AppState, ownProps: Props) => ({ |
||||
|
members: getGroupMembers(state, ownProps.group), |
||||
|
}) |
||||
|
|
||||
interface Props { |
|
||||
members: User[] |
|
||||
} |
|
||||
|
const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({ |
||||
|
fetchGroupMembers: () => { |
||||
|
try { |
||||
|
dispatch(fetchGroupMembers(ownProps.group)) |
||||
|
} catch (err) { |
||||
|
handleApiError(err, dispatch) |
||||
|
} |
||||
|
}, |
||||
|
}) |
||||
|
|
||||
const MemberList: FC<Props> = ({ members }) => ( |
|
||||
<div className="is-flex"> |
|
||||
{members.map(member => <MemberListItem key={member.id} member={member} />)} |
|
||||
</div> |
|
||||
) |
|
||||
|
|
||||
export default MemberList |
|
||||
|
export default connect( |
||||
|
mapStateToProps, |
||||
|
mapDispatchToProps |
||||
|
)(MemberList) |
@ -0,0 +1,25 @@ |
|||||
|
import React, { FC, useEffect } from 'react' |
||||
|
import noop from 'lodash/noop' |
||||
|
import { User } from 'src/types' |
||||
|
|
||||
|
import MemberListItem from './member-list-item' |
||||
|
|
||||
|
export interface Props { |
||||
|
group: string |
||||
|
members?: User[] |
||||
|
fetchGroupMembers?: () => void |
||||
|
} |
||||
|
|
||||
|
const MemberList: FC<Props> = ({ group, members = [], fetchGroupMembers = noop }) => { |
||||
|
useEffect(() => { |
||||
|
fetchGroupMembers() |
||||
|
}, [group]) |
||||
|
|
||||
|
return ( |
||||
|
<div className="is-flex"> |
||||
|
{members.map(member => <MemberListItem key={member.id} member={member} />)} |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
export default MemberList |
@ -0,0 +1,11 @@ |
|||||
|
import React, { FC } from 'react' |
||||
|
import PageHeader from 'src/components/page-header' |
||||
|
|
||||
|
const Loading: FC = () => ( |
||||
|
<div> |
||||
|
<PageHeader title="Loading..." /> |
||||
|
<div className="main-content"></div> |
||||
|
</div> |
||||
|
) |
||||
|
|
||||
|
export default Loading |
@ -1,7 +1,12 @@ |
|||||
import { schema } from 'normalizr' |
import { schema } from 'normalizr' |
||||
|
import { EntityType } from 'src/types' |
||||
|
|
||||
export const groupSchema = new schema.Entity('groups') |
|
||||
|
export const groupSchema = new schema.Entity(EntityType.Group) |
||||
|
|
||||
export const userSchema = new schema.Entity('users', { |
|
||||
|
export const userSchema = new schema.Entity(EntityType.User, { |
||||
group: groupSchema, |
group: groupSchema, |
||||
}) |
}) |
||||
|
|
||||
|
export const logSchema = new schema.Entity(EntityType.Log, { |
||||
|
user: userSchema, |
||||
|
}) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue