Skip to content

Commit

Permalink
feat(pages/home): add list of applications
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeysova committed Jun 28, 2022
1 parent 971f059 commit cf09746
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 14 deletions.
22 changes: 21 additions & 1 deletion src/pages/home/model.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
import { attach, createEvent, createStore, sample } from 'effector';
import { not } from 'patronum';
import { not, spread } from 'patronum';

import { historyPush } from 'features/navigation';
import { $session, checkAuthenticated } from 'features/session';

import * as api from 'shared/api';
import { createStart } from 'shared/lib/page-routing';

import { Application } from './types';

export const pageStarted = createStart();

export const logoutClicked = createEvent();

export const $fullName = createStore<string>('');
export const $email = createStore<string>('');
export const $showError = createStore<boolean>(false);
export const $applicationsInstalled = createStore<Application[]>([]);
export const $applicationsAvailable = createStore<Application[]>([]);

const sessionDeleteFx = attach({ effect: api.sessionDelete });
const applicationsListFx = attach({ effect: api.applicationsList });
const pageReady = checkAuthenticated({ when: pageStarted });

$showError.reset(pageReady);

sample({
clock: pageReady,
fn: () => ({ body: {} }),
target: applicationsListFx,
});

spread({
source: applicationsListFx.doneData.map((response) => response.answer),
targets: {
available: $applicationsAvailable,
installed: $applicationsInstalled,
},
});

sample({
clock: $session,
fn: (session) => `${session?.firstName} ${session?.lastName}`,
Expand All @@ -46,3 +65,4 @@ sample({
});

$showError.on(sessionDeleteFx.fail, () => true);
$showError.on(applicationsListFx.fail, () => true);
49 changes: 48 additions & 1 deletion src/pages/home/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { reflect, variant } from '@effector/reflect/ssr';
import { createEvent, createStore } from 'effector';
import { useStore } from 'effector-react/scope';
import { useList, useStore } from 'effector-react/scope';
import React from 'react';

import { AccessoCard, ButtonPrimary, FailureText } from 'shared/design';
import { CenterCardTemplate } from 'shared/ui';

import { Application } from './types';

//#region Ports
export const logoutClicked = createEvent<React.MouseEvent<HTMLButtonElement>>();

export const $fullName = createStore('');
export const $email = createStore('');
export const $showError = createStore(false);
export const $applicationsInstalled = createStore<Application[]>([]);
export const $applicationsAvailable = createStore<Application[]>([]);
//#endregion

export const HomePage = () => {
Expand All @@ -28,11 +32,39 @@ export const HomePage = () => {
<LogoutButton>Log out</LogoutButton>
</div>
</div>
<InstalledApplications />
<AvailableApplications />
</AccessoCard>
</CenterCardTemplate>
);
};

function InstalledApplications() {
const installed = useStore($applicationsInstalled);
if (installed.length === 0) return null;

return (
<ApplicationsSection title="Installed applications">
{installed.map((application) => (
<div key={application.id}>{application.title}</div>
))}
</ApplicationsSection>
);
}

function AvailableApplications() {
const available = useStore($applicationsAvailable);
if (available.length === 0) return null;

return (
<ApplicationsSection title="Available to install">
{available.map((application) => (
<div key={application.id}>{application.title}</div>
))}
</ApplicationsSection>
);
}

const ErrorBlock = variant({
source: $showError.map(String),
cases: {
Expand All @@ -50,3 +82,18 @@ const LogoutButton = reflect({
onClick: logoutClicked,
},
});

function ApplicationsSection({
title,
children,
}: {
title: string;
children: React.ReactNode | null;
}) {
return (
<div className="space-y-4">
<h2 className="text-2xl font-semibold select-none">{title}</h2>
<div className="flex flex-col space-y-4 text-3xl">{children}</div>
</div>
);
}
3 changes: 3 additions & 0 deletions src/pages/home/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ApplicationsListDone } from 'shared/api';

export type Application = ApplicationsListDone['answer']['installed'][number];
81 changes: 69 additions & 12 deletions src/shared/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// ---
// This file is automatically generated by openapi with preset effector-openapi-preset
// Do not edit this file directly. Instead open openapi config file and follow the link in "file"
import { createEffect } from 'effector';
import * as typed from 'typed-contracts';
import { createEffect } from 'effector';

import { requestFx } from './request';

Expand Down Expand Up @@ -64,7 +64,7 @@ function parseByStatus<

//#endregion prebuilt code/* --- */
//#region oauthAuthorizeRequest
type OauthAuthorizeRequest = {
export type OauthAuthorizeRequest = {
body: {
/* responseType is set to code indicating that you want an authorization code as the response. */
responseType: 'code';
Expand Down Expand Up @@ -180,7 +180,7 @@ export const oauthAuthorizeRequest = createEffect<

/* --- */
//#region accessRecoverySendEmail
type AccessRecoverySendEmail = {
export type AccessRecoverySendEmail = {
body: {
email: string;
};
Expand Down Expand Up @@ -235,7 +235,7 @@ export const accessRecoverySendEmail = createEffect<

/* --- */
//#region accessRecoverySetPassword
type AccessRecoverySetPassword = {
export type AccessRecoverySetPassword = {
body: {
password: string;
code: string;
Expand Down Expand Up @@ -289,7 +289,7 @@ export const accessRecoverySetPassword = createEffect<

/* --- */
//#region registerRequest
type RegisterRequest = {
export type RegisterRequest = {
body: {
email: string;
};
Expand Down Expand Up @@ -347,7 +347,7 @@ export const registerRequest = createEffect<

/* --- */
//#region registerConfirmation
type RegisterConfirmation = {
export type RegisterConfirmation = {
body: {
confirmationCode: string;
firstName: string;
Expand Down Expand Up @@ -410,7 +410,7 @@ export const registerConfirmation = createEffect<

/* --- */
//#region sessionCreate
type SessionCreate = {
export type SessionCreate = {
body: {
email: string;
password: string;
Expand Down Expand Up @@ -465,7 +465,7 @@ export const sessionCreate = createEffect<SessionCreate, SessionCreateDone, Sess

/* --- */
//#region sessionGet
type SessionGet = {};
export type SessionGet = {};

/* Session exists */
export const sessionGetOk = typed.object({
Expand Down Expand Up @@ -516,7 +516,7 @@ export const sessionGet = createEffect<SessionGet, SessionGetDone, SessionGetFai

/* --- */
//#region sessionDelete
type SessionDelete = {
export type SessionDelete = {
body: {
deleteAllSessions: boolean;
};
Expand Down Expand Up @@ -575,7 +575,7 @@ export const sessionDelete = createEffect<SessionDelete, SessionDeleteDone, Sess

/* --- */
//#region accountEdit
type AccountEdit = {
export type AccountEdit = {
body: {
firstName: string;
lastName: string;
Expand Down Expand Up @@ -642,7 +642,7 @@ export const accountEdit = createEffect<AccountEdit, AccountEditDone, AccountEdi

/* --- */
//#region applicationGet
type ApplicationGet = {
export type ApplicationGet = {
body?: {
/* Application id */
applicationId: string;
Expand All @@ -656,7 +656,7 @@ export const applicationGetOk = typed.object({
id: typed.string,
title: typed.string,
allowedRegistrations: typed.boolean,
avatar: typed.string.optional,
avatar: typed.string.maybe,
}),
});
export type ApplicationGetDone = {
Expand Down Expand Up @@ -699,3 +699,60 @@ export const applicationGet = createEffect<ApplicationGet, ApplicationGetDone, A
},
});
//#endregion applicationGet

/* --- */
//#region applicationsList
export type ApplicationsList = {};

/* Applications list */
export const applicationsListOk = typed.object({
installed: typed.array(
typed.object({
id: typed.string,
title: typed.string,
allowedRegistrations: typed.boolean,
avatar: typed.string.maybe,
}),
),
available: typed.array(
typed.object({
id: typed.string,
title: typed.string,
allowedRegistrations: typed.boolean,
avatar: typed.string.maybe,
}),
),
});
export type ApplicationsListDone = {
status: 'ok';
answer: typed.Get<typeof applicationsListOk>;
};

/* Something went wrong */
export const applicationsListInternalServerError = typed.nul;
export type ApplicationsListFail =
| {
status: 'internal_server_error';
error: typed.Get<typeof applicationsListInternalServerError>;
}
| GenericErrors;

/* List available and installed applications for the user */
export const applicationsList = createEffect<
ApplicationsList,
ApplicationsListDone,
ApplicationsListFail
>({
async handler() {
const name = 'applicationsList.body';
const response = await requestFx({
path: '/applications.list',
method: 'POST',
});
return parseByStatus(name, response, {
200: ['ok', applicationsListOk],
500: ['internal_server_error', applicationsListInternalServerError],
});
},
});
//#endregion applicationsList

0 comments on commit cf09746

Please sign in to comment.