Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert Stores to use Classes #5

Merged
merged 5 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 25 additions & 26 deletions src/components/pages/about-page/AboutPage.store.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
import { makeAutoObservable } from 'mobx';
import { observable } from 'mobx';
import { getErrorRequest } from '../../../domains/shows/shows.services';
import { initialResponseStatus } from '../../../utils/mobx.utils';
import { ApiResponse } from '../../../utils/http/http.types';
import { getGlobalStore } from '../../shared/global-store-provider/GlobalStoreProvider';

export class AboutPageStore {
globalStore = getGlobalStore();
errorExampleResults = initialResponseStatus<null>(null);
export const AboutPageStore = () =>
observable({
globalStore: getGlobalStore(),
errorExampleResults: initialResponseStatus<null>(null),

constructor() {
makeAutoObservable(this);
}
/**
* Store initializer. Should only be called once.
*/
*init() {
yield Promise.all([this.loadSomething()]);
},

/**
* Store initializer. Should only be called once.
*/
*init() {
yield Promise.all([this.loadSomething()]);
}
*loadSomething() {
const response: ApiResponse<null> = yield getErrorRequest();

*loadSomething() {
const response: ApiResponse<null> = yield getErrorRequest();
this.errorExampleResults = {
data: this.errorExampleResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};

this.errorExampleResults = {
data: this.errorExampleResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};
if (response.error) {
const message = `${response.statusCode}: ${response.error.message}`;

if (response.error) {
const message = `${response.statusCode}: ${response.error.message}`;
this.globalStore.toastStore.enqueueToast(message, 'error');
}
},
});

this.globalStore.toastStore.enqueueToast(message, 'error');
}
}
}
export type AboutPageStore = ReturnType<typeof AboutPageStore>;
81 changes: 42 additions & 39 deletions src/components/pages/episodes-page/EpisodesPage.store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { observable } from 'mobx';
import { makeAutoObservable } from 'mobx';
import groupBy from 'lodash.groupby';
import orderBy from 'lodash.orderby';
import { IEpisode, IEpisodeTable } from '../../../domains/shows/shows.types';
Expand All @@ -7,41 +7,44 @@ import { ApiResponse } from '../../../utils/http/http.types';
import { getGlobalStore } from '../../shared/global-store-provider/GlobalStoreProvider';
import { EpisodesToggleOption } from './episodes-toggle/EpisodesToggle.constants';

export const EpisodesPageStore = (episodesResults: ApiResponse<IEpisode[]>) =>
observable({
globalStore: getGlobalStore(),
sortType: EpisodesToggleOption.ASC,
episodesResults: episodesResults,

get sortedTableData(): IEpisodeTable[] {
return orderBy(this.generateTableData, 'title', this.sortType);
},

get generateTableData(): IEpisodeTable[] {
if (this.episodesResults.error) {
return [];
}

const seasons: { [season: string]: IEpisode[] } = groupBy(this.episodesResults.data, 'season');

return Object.entries(seasons).map(([season, models]) => {
return {
title: `Season ${season}`,
rows: models.map((model) => ({
episode: model.number,
name: model.name,
date: dayjs(model.airdate).format('MMM D, YYYY'),
image: model.image?.medium ?? '',
})),
};
});
},

setSortType(sortType: EpisodesToggleOption): void {
this.sortType = sortType;

this.globalStore.toastStore.enqueueToast('Nice! You just sorted Server-Side Rendered Content.', 'info');
},
});

export type EpisodesPageStore = ReturnType<typeof EpisodesPageStore>;
export class EpisodesPageStore {
readonly globalStore = getGlobalStore();
sortType = EpisodesToggleOption.ASC;
episodesResults: ApiResponse<IEpisode[]>;

constructor(episodesResults: ApiResponse<IEpisode[]>) {
this.episodesResults = episodesResults;

makeAutoObservable(this);
}

get sortedTableData(): IEpisodeTable[] {
return orderBy(this.generateTableData, 'title', this.sortType);
}

get generateTableData(): IEpisodeTable[] {
if (this.episodesResults.error) {
return [];
}

const seasons: { [season: string]: IEpisode[] } = groupBy(this.episodesResults.data, 'season');

return Object.entries(seasons).map(([season, models]) => {
return {
title: `Season ${season}`,
rows: models.map((model) => ({
episode: model.number,
name: model.name,
date: dayjs(model.airdate).format('MMM D, YYYY'),
image: model.image?.medium ?? '',
})),
};
});
}

setSortType(sortType: EpisodesToggleOption): void {
this.sortType = sortType;

this.globalStore.toastStore.enqueueToast('Nice! You just sorted Server-Side Rendered Content.', 'info');
}
}
102 changes: 52 additions & 50 deletions src/components/pages/index-page/IndexPage.store.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,58 @@
import { observable } from 'mobx';
import { makeAutoObservable } from 'mobx';
import { getCastsRequest, getShowRequest } from '../../../domains/shows/shows.services';
import { initialResponseStatus } from '../../../utils/mobx.utils';
import { ICast, IShow } from '../../../domains/shows/shows.types';
import { ApiResponse } from '../../../utils/http/http.types';
import { defaultShowId } from '../../../domains/shows/shows.constants';
import orderBy from 'lodash.orderby';

export const IndexPageStore = () =>
observable({
// globalStore: getGlobalStore(),
sortValue: '',
showResults: initialResponseStatus<IShow | null>(null),
castsResults: initialResponseStatus<ICast[]>([]),

get isRequesting(): boolean {
return [this.showResults.isRequesting, this.castsResults.isRequesting].some(Boolean);
},

get actors(): ICast[] {
return orderBy(this.castsResults.data, (cast) => cast.person[this.sortValue], 'asc');
},

setSortOption(sortValue: string): void {
this.sortValue = sortValue;
},

/**
* Store initializer. Should only be called once.
*/
*init() {
yield Promise.all([this.loadShow(), this.loadCasts()]);
},

*loadShow() {
const response: ApiResponse<IShow> = yield getShowRequest(defaultShowId);

this.showResults = {
data: this.showResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};
},

*loadCasts() {
const response: ApiResponse<ICast[]> = yield getCastsRequest(defaultShowId);

this.castsResults = {
data: this.castsResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};
},
});

export type IndexPageStore = ReturnType<typeof IndexPageStore>;
import { getGlobalStore } from '../../shared/global-store-provider/GlobalStoreProvider';

export class IndexPageStore {
readonly globalStore = getGlobalStore();
sortValue = '';
showResults = initialResponseStatus<IShow | null>(null);
castsResults = initialResponseStatus<ICast[]>([]);

constructor() {
makeAutoObservable(this);
}

get isRequesting(): boolean {
return [this.showResults.isRequesting, this.castsResults.isRequesting].some(Boolean);
}

get actors(): ICast[] {
return orderBy(this.castsResults.data, (cast) => cast.person[this.sortValue], 'asc');
}

setSortOption(sortValue: string) {
this.sortValue = sortValue;
}

/**
* Store initializer. Should only be called once.
*/
*init() {
yield Promise.all([this.loadShow(), this.loadCasts()]);
}

*loadShow() {
const response: ApiResponse<IShow> = yield getShowRequest(defaultShowId);

this.showResults = {
data: this.showResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};
}

*loadCasts() {
const response: ApiResponse<ICast[]> = yield getCastsRequest(defaultShowId);

this.castsResults = {
data: this.castsResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};
}
}
2 changes: 1 addition & 1 deletion src/pages/about/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { observer } from 'mobx-react-lite';
interface IProps {}

const AboutRoute: NextPage<IProps> = observer((props) => {
const [localStore] = useState(new AboutPageStore());
const [localStore] = useState(AboutPageStore());

useEffect(() => {
localStore.init();
Expand Down
2 changes: 1 addition & 1 deletion src/pages/episodes/[episode_id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface IProps {
}

const EpisodesRoute: NextPage<IProps> = observer((props) => {
const [localStore] = useState(EpisodesPageStore(props.episodesResults));
const [localStore] = useState(new EpisodesPageStore(props.episodesResults));

return (
<LocalStoreProvider localStore={localStore}>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { observer } from 'mobx-react-lite';
interface IProps {}

const IndexRoute: NextPage<IProps> = observer((props) => {
const [localStore] = useState(IndexPageStore());
const [localStore] = useState(new IndexPageStore());

useEffect(() => {
localStore.init();
Expand Down
4 changes: 2 additions & 2 deletions src/stores/GlobalStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export default class GlobalStore {
readonly toastStore: ToastGlobalStore;

constructor() {
this.authStore = AuthGlobalStore(this);
this.toastStore = ToastGlobalStore(this);
this.authStore = new AuthGlobalStore(this);
this.toastStore = new ToastGlobalStore(this);
}

async hydrate(initialState?: Partial<GlobalStore>) {
Expand Down
76 changes: 40 additions & 36 deletions src/stores/auth/AuthGlobalStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { observable } from 'mobx';
import { makeAutoObservable } from 'mobx';
import GlobalStore from '../GlobalStore';
import { getUserRequest } from '../../domains/auth/auth.services';
import { ApiResponse } from '../../utils/http/http.types';
Expand All @@ -7,49 +7,53 @@ import { Routes } from '../../constants/Routes.constants';
import { IUser, IUserResponse } from '../../domains/auth/auth.types';
import Router from 'next/router';

export const AuthGlobalStore = (globalStore: GlobalStore) =>
observable({
authResults: initialResponseStatus<IUserResponse | null>(null, false),
export class AuthGlobalStore {
readonly globalStore: GlobalStore;
authResults = initialResponseStatus<IUserResponse | null>(null, false);

get isAuthenticated(): boolean {
return Boolean(this.authResults.data);
},
constructor(globalStore: GlobalStore) {
this.globalStore = globalStore;

get user(): IUser | null {
if (this.authResults.data) {
return this.authResults.data.results[0];
}
makeAutoObservable(this);
}

return null;
},
get isAuthenticated(): boolean {
return Boolean(this.authResults.data);
}

get userFullName(): string {
return `${this.user?.name?.first} ${this.user?.name?.last}`.trim();
},
get user(): IUser | null {
if (this.authResults.data) {
return this.authResults.data.results[0];
}

*signIn() {
this.authResults.isRequesting = true;
return null;
}

const response: ApiResponse<IUserResponse> = yield getUserRequest();
get userFullName(): string {
return `${this.user?.name?.first} ${this.user?.name?.last}`.trim();
}

this.authResults = {
data: this.authResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};
*signIn() {
this.authResults.isRequesting = true;

if (this.user) {
globalStore.toastStore.enqueueToast(`Welcome ${this.userFullName}`, 'success');
} else {
globalStore.toastStore.enqueueToast('Sign In Issue. Try Again.', 'error');
}
},
const response: ApiResponse<IUserResponse> = yield getUserRequest();

signOut(): void {
this.authResults = initialResponseStatus(null, false);
this.authResults = {
data: this.authResults.data,
isRequesting: false,
...response, // Overwrites the default data prop or adds an error. Also adds the statusCode.
};

Router.router?.push(Routes.Index);
},
});
if (this.user) {
this.globalStore.toastStore.enqueueToast(`Welcome ${this.userFullName}`, 'success');
} else {
this.globalStore.toastStore.enqueueToast('Sign In Issue. Try Again.', 'error');
}
}

export type AuthGlobalStore = ReturnType<typeof AuthGlobalStore>;
signOut(): void {
this.authResults = initialResponseStatus(null, false);

Router.router?.push(Routes.Index);
}
}
Loading