Dwayne Harris 5 years ago
parent
commit
30a6ebb5e4
  1. 64
      src/actions/apps.ts
  2. 107
      src/actions/groups.ts
  3. 40
      src/actions/lists.ts
  4. 47
      src/actions/posts.ts
  5. 3
      src/components/pages/self.tsx
  6. 9
      src/components/pages/view-user.tsx
  7. 17
      src/components/post-list.tsx
  8. 40
      src/components/post.tsx
  9. 35
      src/components/user.tsx
  10. 50
      src/reducers/apps.ts
  11. 93
      src/reducers/groups.ts
  12. 42
      src/reducers/lists.ts
  13. 17
      src/selectors/apps.ts
  14. 2
      src/selectors/composer.ts
  15. 24
      src/selectors/groups.ts
  16. 15
      src/selectors/lists.ts
  17. 9
      src/selectors/posts.ts
  18. 6
      src/store/index.ts
  19. 33
      src/styles/app.scss
  20. 82
      src/types/store.ts

64
src/actions/apps.ts

@ -1,64 +1,14 @@
import { Action } from 'redux'
import { apiFetch } from 'src/api'
import { setEntities } from 'src/actions/entities'
import { startRequest, finishRequest } from 'src/actions/requests'
import { setFieldNotification } from 'src/actions/forms'
import { listSet, listAppend } from 'src/actions/lists'
import { objectToQuerystring } from 'src/utils'
import { normalize } from 'src/utils/normalization'
import { EntityListKey } from 'src/types'
import { AppThunkAction, RequestKey, EntityType, App, AvailabilityResponse, NotificationType }from 'src/types'
export interface AppendAppsAction extends Action {
type: 'APPS_APPEND_APPS'
payload: {
items: string[]
continuation?: string
}
}
export interface ClearAppsAction extends Action {
type: 'APPS_CLEAR_APPS'
}
export interface AppendCreatedAppsAction extends Action {
type: 'APPS_APPEND_CREATED_APPS'
payload: {
items: string[]
continuation?: string
}
}
export interface ClearCreatedAppsAction extends Action {
type: 'APPS_CLEAR_CREATED_APPS'
}
export type AppsActions = AppendAppsAction | ClearAppsAction | AppendCreatedAppsAction | ClearCreatedAppsAction
export const appendApps = (apps: string[], continuation?: string): AppendAppsAction => ({
type: 'APPS_APPEND_APPS',
payload: {
items: apps,
continuation,
}
})
export const clearApps = (): ClearAppsAction => ({
type: 'APPS_CLEAR_APPS',
})
export const appendCreatedApps = (apps: string[], continuation?: string): AppendCreatedAppsAction => ({
type: 'APPS_APPEND_CREATED_APPS',
payload: {
items: apps,
continuation,
}
})
export const clearCreatedApps = (): ClearCreatedAppsAction => ({
type: 'APPS_CLEAR_CREATED_APPS',
})
interface AppsResponse {
apps: App[]
continuation?: string
@ -75,7 +25,13 @@ export const fetchApps = (sort?: string, continuation?: string): AppThunkAction
const apps = normalize(response.apps, EntityType.App)
dispatch(setEntities(apps.entities))
dispatch(appendApps(apps.keys, response.continuation))
if (continuation) {
dispatch(listAppend(EntityListKey.Apps, apps.keys, response.continuation))
} else {
dispatch(listSet(EntityListKey.Apps, apps.keys, response.continuation))
}
dispatch(finishRequest(RequestKey.FetchApps, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchApps, false))
@ -94,7 +50,7 @@ export const fetchCreatedApps = (sort?: string): AppThunkAction => async dispatc
const apps = normalize(response.apps, EntityType.App)
dispatch(setEntities(apps.entities))
dispatch(appendCreatedApps(apps.keys, response.continuation))
dispatch(listSet(EntityListKey.CreatedApps, apps.keys))
dispatch(finishRequest(RequestKey.FetchSelfApps, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchSelfApps, false))

107
src/actions/groups.ts

@ -2,85 +2,12 @@ import { Action } from 'redux'
import { apiFetch } from 'src/api'
import { setEntities } from 'src/actions/entities'
import { listSet, listAppend } from 'src/actions/lists'
import { startRequest, finishRequest } from 'src/actions/requests'
import { objectToQuerystring } from 'src/utils'
import { normalize } from 'src/utils/normalization'
import { AppThunkAction, Entity, RequestKey, EntityType, User } from 'src/types'
export interface AppendGroupsAction extends Action {
type: 'GROUPS_APPEND_GROUPS'
payload: {
items: string[]
continuation?: string
}
}
export interface ClearGroupsAction extends Action {
type: 'GROUPS_CLEAR_GROUPS'
}
export interface AppendLogsAction extends Action {
type: 'GROUPS_APPEND_LOGS'
payload: {
items: string[]
continuation?: string
}
}
export interface ClearLogsAction extends Action {
type: 'GROUPS_CLEAR_LOGS'
}
export interface AppendInvitationsAction extends Action {
type: 'GROUPS_APPEND_INVITATIONS'
payload: {
items: string[]
continuation?: string
}
}
export interface ClearInvitationsAction extends Action {
type: 'GROUPS_CLEAR_INVITATIONS'
}
export type GroupsActions = AppendGroupsAction | ClearGroupsAction | AppendLogsAction | ClearLogsAction | AppendInvitationsAction | ClearInvitationsAction
export const appendGroups = (groups: string[], continuation?: string): AppendGroupsAction => ({
type: 'GROUPS_APPEND_GROUPS',
payload: {
items: groups,
continuation,
},
})
export const clearGroups = (): ClearGroupsAction => ({
type: 'GROUPS_CLEAR_GROUPS',
})
export const appendLogs = (logs: string[], continuation?: string): AppendLogsAction => ({
type: 'GROUPS_APPEND_LOGS',
payload: {
items: logs,
continuation,
},
})
export const clearLogs = (): ClearLogsAction => ({
type: 'GROUPS_CLEAR_LOGS',
})
export const appendInvitations = (invitations: string[], continuation?: string): AppendInvitationsAction => ({
type: 'GROUPS_APPEND_INVITATIONS',
payload: {
items: invitations,
continuation,
},
})
export const clearInvitations = (): ClearInvitationsAction => ({
type: 'GROUPS_CLEAR_INVITATIONS',
})
import { AppThunkAction, Entity, RequestKey, EntityType, User, EntityListKey } from 'src/types'
export const fetchGroup = (id: string): AppThunkAction => {
return async dispatch => {
@ -118,7 +45,13 @@ export const fetchGroups = (sort?: string, continuation?: string): AppThunkActio
const groups = normalize(response.groups, EntityType.Group)
dispatch(setEntities(groups.entities))
dispatch(appendGroups(groups.keys, response.continuation))
if (continuation) {
dispatch(listAppend(EntityListKey.Groups, groups.keys, response.continuation))
} else {
dispatch(listSet(EntityListKey.Groups, groups.keys, response.continuation))
}
dispatch(finishRequest(RequestKey.FetchGroups, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchGroups, false))
@ -142,6 +75,13 @@ export const fetchGroupMembers = (id: string, type?: string, continuation?: stri
const users = normalize(response.members, EntityType.User)
dispatch(setEntities(users.entities))
if (continuation) {
dispatch(listAppend(EntityListKey.GroupMembers, users.keys, response.continuation))
} else {
dispatch(listSet(EntityListKey.GroupMembers, users.keys, response.continuation))
}
dispatch(finishRequest(RequestKey.FetchGroupMembers, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchGroupMembers, false))
@ -162,10 +102,16 @@ export const fetchLogs = (id: string, continuation?: string): AppThunkAction =>
path: `/api/group/${id}/logs?${objectToQuerystring({ continuation })}`,
})
const users = normalize(response.logs, EntityType.Log)
const logs = normalize(response.logs, EntityType.Log)
dispatch(setEntities(logs.entities))
if (continuation) {
dispatch(listAppend(EntityListKey.Logs, logs.keys, response.continuation))
} else {
dispatch(listSet(EntityListKey.Logs, logs.keys, response.continuation))
}
dispatch(setEntities(users.entities))
dispatch(appendLogs(users.keys, response.continuation))
dispatch(finishRequest(RequestKey.FetchGroupLogs, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchGroupLogs, false))
@ -212,8 +158,9 @@ export const fetchInvitations = (id: string): AppThunkAction => async dispatch =
})
const invitations = normalize(response.invitations, EntityType.Invitation)
dispatch(setEntities(invitations.entities))
dispatch(appendInvitations(invitations.keys, response.continuation))
dispatch(listSet(EntityListKey.Invitations, invitations.keys, response.continuation))
dispatch(finishRequest(RequestKey.FetchInvitations, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchInvitations, false))

40
src/actions/lists.ts

@ -0,0 +1,40 @@
import { Action } from 'redux'
import { EntityListKey } from 'src/types'
export interface ListAppendAction extends Action {
type: 'LISTS_APPEND'
payload: {
key: string
entities: string[]
continuation?: string
}
}
export interface ListSetAction extends Action {
type: 'LISTS_SET'
payload: {
key: string
entities: string[]
continuation?: string
}
}
export type ListsActions = ListAppendAction | ListSetAction
export const listAppend = (key: string, entities: string[], continuation?: string): ListAppendAction => ({
type: 'LISTS_APPEND',
payload: {
key,
entities,
continuation,
},
})
export const listSet = (key: string, entities: string[], continuation?: string): ListSetAction => ({
type: 'LISTS_SET',
payload: {
key,
entities,
continuation,
},
})

47
src/actions/posts.ts

@ -2,37 +2,12 @@ import { Action } from 'redux'
import { apiFetch } from 'src/api'
import { setEntities } from 'src/actions/entities'
import { listSet, listAppend } from 'src/actions/lists'
import { startRequest, finishRequest } from 'src/actions/requests'
import { objectToQuerystring } from 'src/utils'
import { normalize } from 'src/utils/normalization'
import { AppThunkAction, Entity, RequestKey, EntityType, User, Post } from 'src/types'
export interface AppendPostsAction extends Action {
type: 'POSTS_APPEND_POSTS'
payload: {
items: string[]
continuation?: string
}
}
export interface ClearPostsAction extends Action {
type: 'POSTS_CLEAR_POSTS'
}
export type PostsActions = AppendPostsAction | ClearPostsAction
export const appendPosts = (posts: string[], continuation?: string): AppendPostsAction => ({
type: 'POSTS_APPEND_POSTS',
payload: {
items: posts,
continuation,
},
})
export const clearPosts = (): ClearPostsAction => ({
type: 'POSTS_CLEAR_POSTS',
})
import { AppThunkAction, Entity, RequestKey, EntityType, User, Post, EntityListKey } from 'src/types'
interface CreatePostResponse {
id: string
@ -109,7 +84,13 @@ export const fetchTimeline = (continuation?: string): AppThunkAction => async di
const posts = normalize(response.posts, EntityType.Group)
dispatch(setEntities(posts.entities))
dispatch(appendPosts(posts.keys, response.continuation))
if (continuation) {
dispatch(listAppend(EntityListKey.Timeline, posts.keys, response.continuation))
} else {
dispatch(listSet(EntityListKey.Timeline, posts.keys, response.continuation))
}
dispatch(finishRequest(RequestKey.FetchTimeline, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchTimeline, false))
@ -128,7 +109,7 @@ export const fetchUserPosts = (id: string, continuation?: string): AppThunkActio
try {
const response = await apiFetch<UserPostsResponse>({
path: `/api/user/${id}/posts?${objectToQuerystring({ continuation })}`,
path: `/api/user/${id}/posts`,
})
const posts = normalize(response.posts.map(p => ({
@ -137,7 +118,13 @@ export const fetchUserPosts = (id: string, continuation?: string): AppThunkActio
})), EntityType.Post)
dispatch(setEntities(posts.entities))
dispatch(appendPosts(posts.keys, response.continuation))
if (continuation) {
dispatch(listAppend(`posts:${id}`, posts.keys, response.continuation))
} else {
dispatch(listSet(`posts:${id}`, posts.keys, response.continuation))
}
dispatch(finishRequest(RequestKey.FetchUserPosts, true))
} catch (err) {
dispatch(finishRequest(RequestKey.FetchUserPosts, false))

3
src/components/pages/self.tsx

@ -117,6 +117,9 @@ const Self: FC = () => {
{tab === 'settings' &&
<div>
<Link to={`/u/${user.id}`}>View Your Page</Link>
<br /><br />
<div className="field">
<label className="label">ID</label>
<div className="control has-icons-left">

9
src/components/pages/view-user.tsx

@ -9,14 +9,16 @@ import { fetchUser } from 'src/actions/users'
import { fetchUserPosts } from 'src/actions/posts'
import { getEntity } from 'src/selectors/entities'
import { getAuthenticatedUser } from 'src/selectors/authentication'
import { getUserPosts } from 'src/selectors/posts'
import { useDeepCompareEffect, useConfig } from 'src/hooks'
import { setTitle, urlForBlob } from 'src/utils'
import { AppState, EntityType, User, AppThunkDispatch } from 'src/types'
import { AppState, EntityType, User, Post, AppThunkDispatch } from 'src/types'
import PageHeader from 'src/components/page-header'
import UserInfo from 'src/components/user-info'
import Loading from 'src/components/pages/loading'
import PostList from 'src/components/post-list'
interface Params {
id: string
@ -26,6 +28,7 @@ const ViewUser: FC = () => {
const { id } = useParams<Params>()
const self = useSelector<AppState, User | undefined>(getAuthenticatedUser)
const user = useSelector<AppState, User | undefined>(state => getEntity<User>(state, EntityType.User, id))
const posts = useSelector<AppState, Post[]>(state => getUserPosts(state, id))
const dispatch = useDispatch<AppThunkDispatch>()
const config = useConfig()
const history = useHistory()
@ -110,9 +113,9 @@ const ViewUser: FC = () => {
}
</div>
</div>
</div>
<PostList posts={posts} />
</div>
)
}

17
src/components/post-list.tsx

@ -0,0 +1,17 @@
import React, { FC } from 'react'
import { Post } from 'src/types'
import PostComponent from 'src/components/post'
interface Props {
posts: Post[]
}
const PostList: FC<Props> = ({ posts }) => (
<div className="post-list">
{posts.map(post => <PostComponent post={post} />)}
</div>
)
export default PostList

40
src/components/post.tsx

@ -0,0 +1,40 @@
import React, { FC } from 'react'
import { Link } from 'react-router-dom'
import moment from 'moment'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faClock } from '@fortawesome/free-solid-svg-icons'
import { Post } from 'src/types'
import User from 'src/components/user'
interface Props {
post: Post
}
const PostComponent: FC<Props> = ({ post }) => (
<div className="post">
<p>{post.text}</p>
<div className="post-info">
<div>
<User user={post.user} />
</div>
<div>
Awards
</div>
<div>
<span className="icon">
<FontAwesomeIcon icon={faClock} />
</span>
<Link to={`/p/${post.id}`} className="has-text-primary">
{moment(post.created).format('MMMM Do, h:mm A')}
</Link>
</div>
</div>
</div>
)
export default PostComponent

35
src/components/user.tsx

@ -0,0 +1,35 @@
import React, { FC } from 'react'
import { useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { getConfig } from 'src/selectors'
import { urlForBlob } from 'src/utils'
import { AppState, User, Config } from 'src/types'
interface Props {
user: User
}
const UserComponent: FC<Props> = ({ user }) => {
const config = useSelector<AppState, Config>(getConfig)
const imageUrl = user && user.imageUrl ? urlForBlob(config, user.imageUrl) : undefined
return (
<div className="user">
{imageUrl &&
<div className="avatar">
<img src={imageUrl} style={{ width: 32 }} />
</div>
}
<div>
<Link to={`/u/${user.id}`}>
<span className="is-size-5">{user.name}</span> <span className="is-size-6 has-text-weight-bold">@{user.id}</span>
</Link>
<br />
{user.group && <Link className="is-size-6 has-text-success" to={`/c/${user.group.id}`}>{user.group.name}</Link>}
</div>
</div>
)
}
export default UserComponent

50
src/reducers/apps.ts

@ -1,50 +0,0 @@
import { Reducer } from 'redux'
import { AppsActions } from '../actions/apps'
import { AppsState } from '../types'
const initialState: AppsState = {
items: [],
continuation: undefined,
created: {
items: [],
continuation: undefined
}
}
const reducer: Reducer<AppsState, AppsActions> = (state = initialState, action) => {
switch (action.type) {
case 'APPS_APPEND_APPS':
return {
...state,
items: action.payload.items,
continuation: action.payload.continuation,
}
case 'APPS_CLEAR_APPS':
return {
...state,
items: [],
continuation: undefined,
}
case 'APPS_APPEND_CREATED_APPS':
return {
...state,
created: {
items: action.payload.items,
continuation: action.payload.continuation,
},
}
case 'APPS_CLEAR_CREATED_APPS':
return {
...state,
created: {
items: [],
continuation: undefined,
},
}
default:
return state
}
}
export default reducer

93
src/reducers/groups.ts

@ -1,93 +0,0 @@
import { Reducer } from 'redux'
import { GroupsActions } from '../actions/groups'
import { GroupsState } from '../types'
const initialState: GroupsState = {
items: [],
continuation: undefined,
admin: {
invitations: {
items: [],
continuation: undefined,
},
logs: {
items: [],
continuation: undefined,
}
}
}
const reducer: Reducer<GroupsState, GroupsActions> = (state = initialState, action) => {
switch (action.type) {
case 'GROUPS_APPEND_GROUPS':
return {
...state,
items: [
...state.items,
...action.payload.items,
],
continuation: action.payload.continuation,
}
case 'GROUPS_CLEAR_GROUPS':
return {
...state,
items: [],
continuation: undefined,
}
case 'GROUPS_APPEND_LOGS':
return {
...state,
admin: {
...state.admin,
logs: {
items: [
...state.admin.logs.items,
...action.payload.items,
],
continuation: action.payload.continuation,
},
},
}
case 'GROUPS_CLEAR_LOGS':
return {
...state,
admin: {
...state.admin,
logs: {
items: [],
continuation: undefined,
},
},
}
case 'GROUPS_APPEND_INVITATIONS':
return {
...state,
admin: {
...state.admin,
invitations: {
items: [
...state.admin.logs.items,
...action.payload.items,
],
continuation: action.payload.continuation,
},
},
}
case 'GROUPS_CLEAR_INVITATIONS':
return {
...state,
admin: {
...state.admin,
invitations: {
items: [],
continuation: undefined,
},
},
}
default:
return state
}
}
export default reducer

42
src/reducers/lists.ts

@ -0,0 +1,42 @@
import { Reducer } from 'redux'
import { ListsActions } from '../actions/lists'
import { EntityListsState, EntityList } from '../types'
const initialState: EntityListsState = {}
const reducer: Reducer<EntityListsState, ListsActions> = (state = initialState, action) => {
switch (action.type) {
case 'LISTS_APPEND':
const list = state[action.payload.key] || {
entities: [],
continuation: undefined,
checked: 0,
}
return {
...state,
[action.payload.key]: {
entities: [
...list.entities,
...action.payload.entities,
],
continuation: action.payload.continuation,
checked: Date.now(),
},
}
case 'LISTS_SET':
return {
...state,
[action.payload.key]: {
entities: action.payload.entities,
continuation: action.payload.continuation,
checked: Date.now(),
}
}
default:
return state
}
}
export default reducer

17
src/selectors/apps.ts

@ -1,5 +1,16 @@
import { denormalize } from 'src/utils/normalization'
import { AppState, EntityType, App, Installation } from 'src/types'
import { AppState, EntityType, App, EntityListKey } from 'src/types'
export const getApps = (state: AppState) => denormalize(state.apps.items, EntityType.App, state.entities) as App[]
export const getCreatedApps = (state: AppState) => denormalize(state.apps.created.items, EntityType.App, state.entities) as App[]
export const getApps = (state: AppState) => {
const entityList = state.lists[EntityListKey.Apps]
if (!entityList) return []
return denormalize(entityList.entities, EntityType.App, state.entities) as App[]
}
export const getCreatedApps = (state: AppState) => {
const entityList = state.lists[EntityListKey.CreatedApps]
if (!entityList) return []
return denormalize(entityList.entities, EntityType.App, state.entities) as App[]
}

2
src/selectors/composer.ts

@ -1,8 +1,6 @@
import { denormalize } from 'src/utils/normalization'
import { AppState, EntityType, App, Installation } from 'src/types'
export const getApps = (state: AppState) => denormalize(state.apps.items, EntityType.App, state.entities) as App[]
export const getCreatedApps = (state: AppState) => denormalize(state.apps.created.items, EntityType.App, state.entities) as App[]
export const getInstallations = (state: AppState) => denormalize(state.composer.installations, EntityType.Installation, state.entities) as Installation[]
export const getError = (state: AppState) => state.composer.error
export const getHeight = (state: AppState) => state.composer.height

24
src/selectors/groups.ts

@ -1,9 +1,25 @@
import { denormalize } from 'src/utils/normalization'
import { AppState, Group, User, EntityType, GroupLog, Invitation } from 'src/types'
import { AppState, Group, User, EntityType, GroupLog, Invitation, EntityListKey } from 'src/types'
export const getGroups = (state: AppState) => denormalize(state.groups.items, EntityType.Group, state.entities) as Group[]
export const getLogs = (state: AppState) => denormalize(state.groups.admin.logs.items, EntityType.Log, state.entities) as GroupLog[]
export const getInvitations = (state: AppState) => denormalize(state.groups.admin.invitations.items, EntityType.Invitation, state.entities) as Invitation[]
export const getGroups = (state: AppState) => {
const entityList = state.lists[EntityListKey.Groups]
if (!entityList) return []
return denormalize(entityList.entities, EntityType.Group, state.entities) as Group[]
}
export const getLogs = (state: AppState) => {
const entityList = state.lists[EntityListKey.Logs]
if (!entityList) return []
return denormalize(entityList.entities, EntityType.Log, state.entities) as GroupLog[]
}
export const getInvitations = (state: AppState) => {
const entityList = state.lists[EntityListKey.Invitations]
if (!entityList) return []
return denormalize(entityList.entities, EntityType.Invitation, state.entities) as Invitation[]
}
export const getGroupMembers = (state: AppState, group: string) => {
const users = state.entities[EntityType.User]

15
src/selectors/lists.ts

@ -0,0 +1,15 @@
import { AppState } from 'src/types'
export const getEntities = (state: AppState, name: string) => {
const entityList = state.lists[name]
if (!entityList) return []
return entityList.entities
}
export const getLastChecked = (state: AppState, name: string) => {
const entityList = state.lists[name]
if (!entityList) return 0
return entityList.checked
}

9
src/selectors/posts.ts

@ -0,0 +1,9 @@
import { denormalize } from 'src/utils/normalization'
import { AppState, Post, EntityType } from 'src/types'
export const getUserPosts = (state: AppState, id: string) => {
const entityList = state.lists[`posts:${id}`]
if (!entityList) return []
return denormalize(entityList.entities, EntityType.Post, state.entities) as Post[]
}

6
src/store/index.ts

@ -1,13 +1,12 @@
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { AppState } from '../types'
import apps from '../reducers/apps'
import authentication from '../reducers/authentication'
import composer from '../reducers/composer'
import config from '../reducers/config'
import entities from '../reducers/entities'
import forms from '../reducers/forms'
import groups from '../reducers/groups'
import lists from '../reducers/lists'
import menu from '../reducers/menu'
import notifications from '../reducers/notifications'
import registration from '../reducers/registration'
@ -18,13 +17,12 @@ import thunk from 'redux-thunk'
const store = createStore(
combineReducers<AppState>({
apps,
authentication,
composer,
config,
entities,
forms,
groups,
lists,
menu,
notifications,
registration,

33
src/styles/app.scss

@ -153,3 +153,36 @@ div.composer-container {
}
}
}
div.user {
display: flex;
div.avatar {
margin-top: 6px;
margin-right: 10px;
}
}
div.posts-list {
margin: 10px;
}
div.post {
background-color: white;
margin: 10px 0;
}
div.post p {
padding: 20px;
}
div.post-info {
border-top: solid 1px $grey-lighter;
display: flex;
justify-content: space-between;
padding: 0 20px;
}
div.post-info > div {
padding: 10px;
}

82
src/types/store.ts

@ -11,31 +11,41 @@ export enum NotificationType {
export enum RequestKey {
Authenticate = 'authenticate',
CreateApp = 'create_app',
CreateGroup = 'create_group',
CreateInvitation = 'create_invitation',
CreatePost = 'create_post',
FetchAppAvailability = 'fetch_app_availability',
FetchApp = 'fetch_app',
FetchApps = 'fetch_apps',
FetchGroup = 'fetch_group',
FetchGroupAvailability = 'fetch_group_availability',
FetchGroupLogs = 'fetch_group_logs',
FetchGroupMembers = 'fetch_group_members',
FetchGroups = 'fetch_groups',
FetchInstallations = 'fetch_installations',
FetchInvitations = 'fetch_invitations',
FetchPost = 'fetch_post',
FetchTimeline = 'fetch_timeline',
FetchUserPosts = 'fetch_user_posts',
FetchSelfApps = 'fetch_self_apps',
FetchUser = 'fetch_user',
FetchUserAvailability = 'fetch_user_availability',
InstallApp = 'install_app',
UninstallApp = 'uninstall_app',
CreateApp = 'create-app',
CreateGroup = 'create-group',
CreateInvitation = 'create-invitation',
CreatePost = 'create-post',
FetchAppAvailability = 'fetch-app-availability',
FetchApp = 'fetch-app',
FetchApps = 'fetch-apps',
FetchGroup = 'fetch-group',
FetchGroupAvailability = 'fetch-group-availability',
FetchGroupLogs = 'fetch-group-logs',
FetchGroupMembers = 'fetch-group-members',
FetchGroups = 'fetch-groups',
FetchInstallations = 'fetch-installations',
FetchInvitations = 'fetch-invitations',
FetchPost = 'fetch-post',
FetchTimeline = 'fetch-timeline',
FetchUserPosts = 'fetch-user-posts',
FetchSelfApps = 'fetch-self-apps',
FetchUser = 'fetch-user',
FetchUserAvailability = 'fetch-user-availability',
InstallApp = 'install-app',
UninstallApp = 'uninstall-app',
Register = 'register',
UpdateGroup = 'update_group',
UpdateSelf = 'update_self',
UpdateGroup = 'update-group',
UpdateSelf = 'update-self',
}
export enum EntityListKey {
Apps = 'apps',
CreatedApps = 'created-apps',
Groups = 'groups',
GroupMembers = 'group-members',
Logs = 'logs',
Invitations = 'invitations',
Timeline = 'timeline',
}
export type FormValue = string | number | boolean
@ -86,8 +96,9 @@ export interface Form {
}
export interface EntityList {
items: string[]
entities: string[]
continuation?: string
checked: number
}
export interface FormsState {
@ -95,23 +106,10 @@ export interface FormsState {
notification?: FormNotification
}
export interface GroupsAdminState {
invitations: EntityList
logs: EntityList
}
export type GroupsState = EntityList & {
admin: GroupsAdminState
}
export interface RegistrationState {
step: number
}
export type AppsState = EntityList & {
created: EntityList
}
export type ComposerState = {
installations: string[]
selected?: string
@ -119,19 +117,23 @@ export type ComposerState = {
height: number
}
export interface EntityListCollection {
[key: string]: EntityList
}
export type ConfigState = Config
export type RequestsState = APIRequestCollection
export type NotificationsState = Notification[]
export type EntitiesState = EntityStore
export type EntityListsState = EntityListCollection
export interface AppState {
authentication: AuthenticationState
apps: AppsState
composer: ComposerState
config: ConfigState
entities: EntitiesState
forms: FormsState
groups: GroupsState
lists: EntityListsState
menu: MenuState
notifications: NotificationsState
registration: RegistrationState

Loading…
Cancel
Save