diff --git a/src/actions/apps.ts b/src/actions/apps.ts index b724aa6..174e3fe 100644 --- a/src/actions/apps.ts +++ b/src/actions/apps.ts @@ -1,10 +1,11 @@ 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 { objectToQuerystring } from 'src/utils' import { normalize } from 'src/utils/normalization' -import { AppThunkAction, RequestKey, EntityType, App }from 'src/types' +import { AppThunkAction, RequestKey, EntityType, App, AvailabilityResponse, NotificationType, AppThunkDispatch }from 'src/types' interface AppsResponse { apps: App[] @@ -46,3 +47,87 @@ export const fetchSelfApps = (sort?: string): AppThunkAction => async dispatch = throw err } } + +export const checkAppAvailability = (name: string): AppThunkAction => async dispatch => { + dispatch(startRequest(RequestKey.FetchAppAvailability)) + + try { + const { id, available } = await apiFetch({ + path: '/api/app/available', + method: 'post', + body: { + name, + }, + }) + + if (available) { + dispatch(setFieldNotification('name', NotificationType.Success, `${id} is available`)) + } else { + dispatch(setFieldNotification('name', NotificationType.Error, `${id} isn't available`)) + } + + dispatch(finishRequest(RequestKey.FetchAppAvailability, true)) + } catch (err) { + dispatch(finishRequest(RequestKey.FetchAppAvailability, false)) + throw err + } +} + +interface CreateAppOptions { + name: string + about?: string + websiteUrl?: string + companyName?: string + version: string + composerUrl?: string + rendererUrl?: string +} + +interface CreateAppResponse { + id: string +} + +export const createApp = (options: CreateAppOptions): AppThunkAction => async dispatch => { + const { name, about, websiteUrl, companyName, version, composerUrl, rendererUrl } = options + dispatch(startRequest(RequestKey.CreateApp)) + + try { + const { id } = await apiFetch({ + path: '/api/app', + method: 'post', + body: { + name, + about, + websiteUrl, + companyName, + version, + composerUrl, + rendererUrl, + }, + }) + + dispatch(finishRequest(RequestKey.CreateApp, true)) + return id + } catch (err) { + dispatch(finishRequest(RequestKey.CreateApp, false)) + throw err + } +} + +export const fetchApp = (id: string): AppThunkAction => async dispatch => { + dispatch(startRequest(RequestKey.FetchApp)) + + try { + const app = await apiFetch({ + path: `/api/app/${id}`, + method: 'get', + }) + + const apps = normalize([app], EntityType.App) + dispatch(setEntities(apps.entities)) + dispatch(finishRequest(RequestKey.FetchApp, true)) + } catch (err) { + dispatch(finishRequest(RequestKey.FetchApp, false)) + throw err + } +} diff --git a/src/actions/registration.ts b/src/actions/registration.ts index 79a4a5f..e33f477 100644 --- a/src/actions/registration.ts +++ b/src/actions/registration.ts @@ -9,7 +9,7 @@ import { LOCAL_STORAGE_REFRESH_TOKEN_KEY, } from 'src/constants' -import { AppThunkAction, NotificationType, RequestKey } from 'src/types' +import { AppThunkAction, NotificationType, RequestKey, AvailabilityResponse } from 'src/types' export interface SetStepAction extends Action { type: 'REGISTRATION_SET_STEP' @@ -18,11 +18,6 @@ export interface SetStepAction extends Action { export type RegistrationActions = SetStepAction -interface AvailabilityResponse { - id: string - available: boolean -} - export const setStep = (step: number): SetStepAction => ({ type: 'REGISTRATION_SET_STEP', payload: step, diff --git a/src/components/app.tsx b/src/components/app.tsx index 42d6e17..2dc1e6a 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -27,6 +27,7 @@ import Login from './pages/login' import Register from './pages/register' import RegisterGroup from './pages/register-group' import Self from './pages/self' +import ViewApp from './pages/view-app' import '../styles/app.scss' import '../styles/spinner.scss' @@ -84,6 +85,9 @@ const App: FC = () => { + + + diff --git a/src/components/create-group-form.tsx b/src/components/create-group-form.tsx index 4bf1a82..8bc59a3 100644 --- a/src/components/create-group-form.tsx +++ b/src/components/create-group-form.tsx @@ -53,7 +53,7 @@ const CreateGroupForm: FC = () => {
- I agree to the Community terms and conditions. + I agree to the Communities terms and conditions. ) diff --git a/src/components/create-group-step.tsx b/src/components/create-group-step.tsx index fbecb31..6024bcb 100644 --- a/src/components/create-group-step.tsx +++ b/src/components/create-group-step.tsx @@ -6,33 +6,34 @@ import { faBuilding, faArrowLeft } from '@fortawesome/free-solid-svg-icons' import { setFieldNotification } from 'src/actions/forms' import { showNotification } from 'src/actions/notifications' import { setStep } from 'src/actions/registration' -import { getFieldValue } from 'src/selectors/forms' +import { getForm, getFieldValue } from 'src/selectors/forms' import { MAX_ID_LENGTH } from 'src/constants' -import { AppState, AppThunkDispatch, NotificationType } from 'src/types' +import { AppState, AppThunkDispatch, NotificationType, Form } from 'src/types' import CreateGroupForm from './create-group-form' +import { valueFromForm } from 'src/utils' interface Props { register: () => void } const CreateGroupStep: FC = ({ register }) => { - const name = useSelector(state => getFieldValue(state, 'group-name', '')) - const registration = useSelector(state => getFieldValue(state, 'group-registration', '')) - const agree = useSelector(state => getFieldValue(state, 'group-agree', false)) - + const form = useSelector(getForm) const dispatch = useDispatch() - const next = (name: string, registration: string, agree: boolean) => { + const next = () => { let invalid = false - if (!name) { + const name = valueFromForm(form, 'group-name') + const agree = valueFromForm(form, 'group-agree') + + if (!name || name === '') { dispatch(setFieldNotification('group-name', NotificationType.Error, 'This is required')) invalid = true } - if (name.length > MAX_ID_LENGTH) { + if (name && name.length > MAX_ID_LENGTH) { dispatch(setFieldNotification('group-name', NotificationType.Error, `This must be less than ${MAX_ID_LENGTH} characters`)) invalid = true } @@ -72,7 +73,7 @@ const CreateGroupStep: FC = ({ register }) => {

- +

diff --git a/src/components/create-user-step.tsx b/src/components/create-user-step.tsx index 18f028f..1caf38e 100644 --- a/src/components/create-user-step.tsx +++ b/src/components/create-user-step.tsx @@ -7,40 +7,43 @@ import { faUser, faArrowRight } from '@fortawesome/free-solid-svg-icons' import { setFieldNotification } from 'src/actions/forms' import { showNotification } from 'src/actions/notifications' import { setStep } from 'src/actions/registration' -import { getFieldValue } from 'src/selectors/forms' +import { getForm, getFieldValue } from 'src/selectors/forms' import { MAX_ID_LENGTH, MAX_NAME_LENGTH } from 'src/constants' -import { AppState, AppThunkDispatch, NotificationType } from 'src/types' +import { valueFromForm } from 'src/utils' + +import { AppState, AppThunkDispatch, NotificationType, Form } from 'src/types' import CreateUserForm from './create-user-form' const CreateUserStep: FC = () => { - const userId = useSelector(state => getFieldValue(state, 'user-id', '')) - const name = useSelector(state => getFieldValue(state, 'user-name', '')) - const email = useSelector(state => getFieldValue(state, 'user-email', '')) - const password = useSelector(state => getFieldValue(state, 'password', '')) - const agree = useSelector(state => getFieldValue(state, 'user-agree', false)) - + const form = useSelector(getForm) const dispatch = useDispatch() - const next = (userId: string, name: string, email: string, password: string, agree: boolean) => { + const next = () => { let invalid = false - - if (!userId) { + + const userId = valueFromForm(form, 'user-id') + const name = valueFromForm(form, 'user-name') + const email = valueFromForm(form, 'user-email') + const password = valueFromForm(form, 'password') + const agree = valueFromForm(form, 'agree') + + if (!userId || userId === '') { dispatch(setFieldNotification('user-id', NotificationType.Error, 'This is required')) invalid = true } - if (userId.length > MAX_ID_LENGTH) { + if (userId && userId.length > MAX_ID_LENGTH) { dispatch(setFieldNotification('user-id', NotificationType.Error, `This must be less than ${MAX_ID_LENGTH} characters`)) invalid = true } - if (name.length > MAX_NAME_LENGTH) { + if (name && name.length > MAX_NAME_LENGTH) { dispatch(setFieldNotification('user-name', NotificationType.Error, `This must be less than ${MAX_NAME_LENGTH} characters`)) invalid = true } - if (email === '') { + if (!email || email === '') { dispatch(setFieldNotification('user-email', NotificationType.Error, 'This is required')) invalid = true } @@ -51,7 +54,7 @@ const CreateUserStep: FC = () => { invalid = true } - if (password === '') { + if (!password || password === '') { dispatch(setFieldNotification('password', NotificationType.Error, 'This is required')) invalid = true } else { @@ -85,7 +88,7 @@ const CreateUserStep: FC = () => {

-