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

システムメッセージを表示する機能を追加した #90

Merged
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
6 changes: 2 additions & 4 deletions app/actions/authentication/user-authentication-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ export default class UserAuthenticationAction {

/**
* ログアウトする。
* @returns ログアウトに成功したかどうか。
*/
public async logout(token: string): Promise<boolean> {
const response = await this.userAccountManager.logout(token);
return response;
public async logout(token: string): Promise<void> {
await this.userAccountManager.logout(token);
}
}
11 changes: 5 additions & 6 deletions app/actions/authentication/user-registration-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,19 @@ export default class UserRegistrationAction {
* ユーザーを登録する。
* @param mailAddress メールアドレス。
* @param password パスワード。
* @param confirmPassword 再確認パスワード。
* @returns サインアップのレスポンス。
*/
public async register(mailAddress: string, password: string): Promise<SignUpResponse> {
const response = await this.userAccountManager.register(mailAddress, password);
public async register(mailAddress: string, password: string, confirmPassword: string): Promise<SignUpResponse> {
const response = await this.userAccountManager.register(mailAddress, password, confirmPassword);
return response;
}

/**
* ユーザーを削除する。
* @param token トークン。
* @returns 削除に成功したかどうか。
*/
public async delete(token: string): Promise<boolean> {
const response = await this.userAccountManager.delete(token);
return response;
public async delete(token: string): Promise<void> {
await this.userAccountManager.delete(token);
}
}
12 changes: 4 additions & 8 deletions app/actions/user/sns-user-registration-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,16 @@ export default class SnsUserRegistrationAction {
* @param authenticationProviderId 認証プロバイダID。
* @param userName ユーザー名。
* @param currentReleaseInformationId 現在のリリース情報ID。
* @returns 登録に成功したかどうか。
*/
public async register(authenticationProviderId: string, userName: string, currentReleaseInformationId: number): Promise<boolean> {
const response = await this.userProfileManager.register(authenticationProviderId, userName, currentReleaseInformationId);
return response;
public async register(authenticationProviderId: string, userName: string, currentReleaseInformationId: number): Promise<void> {
await this.userProfileManager.register(authenticationProviderId, userName, currentReleaseInformationId);
}

/**
* ユーザーを削除する。
* @param id ユーザーID。
* @returns 削除に成功したかどうか。
*/
public async delete(id: number): Promise<boolean> {
const response = await this.userProfileManager.delete(id);
return response;
public async delete(id: number): Promise<void> {
await this.userProfileManager.delete(id);
}
}
6 changes: 2 additions & 4 deletions app/actions/user/user-setting-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ export default class UserSettingAction {
/**
* ユーザー設定を更新する。
* @param userSetting ユーザー設定。
* @returns 更新に成功したかどうか。
*/
public async editUserSetting(userSetting: UserSetting): Promise<boolean> {
const response = await this.userProfileManager.editUserSetting(userSetting);
return response;
public async editUserSetting(userSetting: UserSetting): Promise<void> {
await this.userProfileManager.editUserSetting(userSetting);
}
}
9 changes: 9 additions & 0 deletions app/contexts/system-message/system-message-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createContext } from "react";

/**
* システムメッセージコンテキスト。
*/
const SystemMessageContext = createContext({
showSystemMessage: (status: "success" | "error", message: string) => {}
});
export default SystemMessageContext;
49 changes: 49 additions & 0 deletions app/contexts/system-message/system-message-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import SystemMessageContext from "./system-message-context";
import { ReactNode } from "react";
import toast, { Toaster, useToaster } from "react-hot-toast";

/**
* システムメッセージプロバイダー。
* @param children 子要素。
* @returns システムメッセージプロバイダー。
*/
const SystemMessageProvider = ({
children,
}: {
children: ReactNode,
}) => {
const showSystemMessage = (status: "success" | "error", message: string) => {
if (!message) return;
switch (status) {
case "success":
toast.success(message);
break;
case "error":
toast.error(message);
break;
}
};

return (
<SystemMessageContext.Provider value={{ showSystemMessage }}>
{children}
<Toaster
position="bottom-right"
toastOptions={{
className: "",
style: {
background: "#363636",
color: "#fff",
},
success: {
duration: 3000,
},
error: {
duration: 4000,
},
}}
/>
</SystemMessageContext.Provider>
);
};
export default SystemMessageProvider;
10 changes: 3 additions & 7 deletions app/libraries/authentication/firebase-client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import systemMessages from "../../messages/system-messages";
import IAuthenticationClient from "./i-authentication-client";
import HttpClient from "../http/http-client";
import SignUpResponse from "../../models/authentication/signup-response";
Expand All @@ -24,22 +25,17 @@ export default class FirebaseClient implements IAuthenticationClient {
constructor() {
if (process.env.RUN_INFRA_TESTS) {
if (!process.env.TEST_FIREBASE_API_KEY) {
throw new Error("TEST_FIREBASE_API_KEYが設定されていません。");
throw new Error(systemMessages.error.authenticationProviderTestEnvironmentVariableError);
}
process.env.FIREBASE_API_KEY = process.env.TEST_FIREBASE_API_KEY;
}
if (!process.env.FIREBASE_API_KEY) {
throw new Error("FIREBASE_API_KEYが設定されていません。");
throw new Error(systemMessages.error.authenticationProviderEnvironmentVariableError);
}
this.firebaseApiKey = process.env.FIREBASE_API_KEY;
}

public async signUp(mailAddress: string, password: string): Promise<SignUpResponse> {
// パスワードの長さが8文字未満、英数字が含まれていない場合、エラーを投げる。
if (password.length < 8 || !password.match(/^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i)) {
throw new Error("パスワードは8文字以上の英数字で設定してください。");
}

// メールアドレスとパスワードでサインアップする。
const endpoint = "v1/accounts:signUp";
const queries = {
Expand Down
22 changes: 22 additions & 0 deletions app/libraries/authentication/sign-up-validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import systemMessages from "../../messages/system-messages";

/**
* サインアップのバリデーションを行うクラス。
*/
export default class SignUpValidator {
/**
* サインアップのバリデーションを行う。
* @param password パスワード。
* @param confirmPassword 再確認パスワード。
* @returns バリデーション結果。
* @throws バリデーションに失敗した場合、エラーを投げる。
*/
public static validate(password: string, confirmPassword: string): boolean {
// パスワードの長さが8文字未満、英数字が含まれていない場合、エラーを投げる。
if (password.length < 8 || !password.match(/^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i)) throw new Error(systemMessages.error.invalidPasswordOnSetting);

// パスワードと再確認パスワードが一致しない場合、エラーを返す。
if (password !== confirmPassword) throw new Error(systemMessages.error.passwordMismatch);
return true;
}
}
53 changes: 40 additions & 13 deletions app/libraries/authentication/user-account-manager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import systemMessages from "../../messages/system-messages";
import SignUpResponse from "../../models/authentication/signup-response";
import IAuthenticationClient from "./i-authentication-client";
import SignInWithEmailPasswordResponse from "../../models/authentication/signin-with-email-password-response";

import SignUpValidator from "./sign-up-validator";

/**
* ユーザー管理を行うクラス。
Expand All @@ -20,21 +21,37 @@ export default class UserAccountManager {
* ユーザーを登録する。
* @param mailAddress メールアドレス。
* @param password パスワード。
* @param confirmPassword 再確認パスワード。
* @returns サインアップのレスポンス。
*/
public async register(mailAddress: string, password: string): Promise<SignUpResponse> {
const response = await this.authenticationClient.signUp(mailAddress, password);
return response;
public async register(mailAddress: string, password: string, confirmPassword: string): Promise<SignUpResponse> {
try {
// ユーザー登録のバリデーションを行う。
SignUpValidator.validate(password, confirmPassword);

// ユーザーを登録する。
const response = await this.authenticationClient.signUp(mailAddress, password);
return response;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.signUpFailed);
}
}

/**
* ユーザーを削除する。
* @param token トークン。
* @returns 削除に成功したかどうか。
*/
public async delete(token: string): Promise<boolean> {
const response = await this.authenticationClient.deleteUser(token);
return response;
public async delete(token: string): Promise<void> {
try {
const response = await this.authenticationClient.deleteUser(token);
if (!response) throw new Error(systemMessages.error.authenticationUserDeletionFailed);
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.authenticationUserDeletionFailed);
}
}

/**
Expand All @@ -44,16 +61,26 @@ export default class UserAccountManager {
* @returns メールアドレスとパスワードでサインインのレスポンス。
*/
public async login(mailAddress: string, password: string): Promise<SignInWithEmailPasswordResponse> {
const response = await this.authenticationClient.signInWithEmailPassword(mailAddress, password);
return response;
try {
const response = await this.authenticationClient.signInWithEmailPassword(mailAddress, password);
return response;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.invalidMailAddressOrPassword);
}
}

/**
* ログアウトする。
* @param token トークン。
* @returns ログアウトに成功したかどうか。
*/
public async logout(token: string): Promise<boolean> {
return true;
public async logout(token: string): Promise<void> {
try {
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.logoutFailed);
}
}
}
11 changes: 9 additions & 2 deletions app/libraries/post/post-interactor.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import systemMessages from "../../messages/system-messages";
import IPostContentRepository from '../../repositories/post/i-post-content-repository';

/**
Expand All @@ -21,7 +22,13 @@ export default class PostInteractor {
* @returns 投稿ID。
*/
public async post(posterId: number, releaseInformationId: number, content: string): Promise<number> {
const postId = await this.postContentRepository.create(posterId, releaseInformationId, content);
return postId;
try {
const postId = await this.postContentRepository.create(posterId, releaseInformationId, content);
return postId;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.postFailed);
}
}
}
13 changes: 11 additions & 2 deletions app/libraries/post/posts-fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import systemMessages from "../../messages/system-messages";
import PostContent from '../../models/post/post-content';
import IPostContentRepository from '../../repositories/post/i-post-content-repository';

Expand All @@ -18,16 +19,24 @@ export default class PostsFetcher {
* ユーザーが設定したリリースバージョン以下の最新の投稿を指定された数取得する。
* @param profileId プロフィールID。
* @param numberOfPosts 取得する投稿数。
* @returns 取得した投稿。
*/
public async fetchLatestPosts(profileId: string, numberOfPosts: number): Promise<PostContent[]> {
const posts = await this.postContentRepository.getLatestLimited(profileId, numberOfPosts);
return posts;
try {
const posts = await this.postContentRepository.getLatestLimited(profileId, numberOfPosts);
return posts;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.postRetrievalFailed);
}
}

/**
* ユーザーが設定したリリースバージョン以下の指定された投稿ID以前の投稿を指定された数取得する。
* @param postId 投稿ID。
* @param numberOfPosts 取得する投稿数。
* @returns 取得した投稿。
*/
public async fetchPostsById(postId: number, numberOfPosts: number): Promise<PostContent[]> {
throw new Error('Method not implemented.');
Expand Down
33 changes: 27 additions & 6 deletions app/libraries/post/release-information-getter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import systemMessages from "../../messages/system-messages";
import ReleaseInformation from "../../models/post/release-information";
import IReleaseInformationRepository from "../../repositories/post/i-release-information-repository";

Expand All @@ -16,18 +17,32 @@ export default class ReleaseInformationGetter {
/**
* リリース情報を取得する。
* @param releaseInformationId リリース情報ID。
* @returns リリース情報。
*/
public async getReleaseInformation(releaseInformationId: number): Promise<ReleaseInformation> {
const response = await this.releaseInformationRepository.get(releaseInformationId);
return response;
try {
const response = await this.releaseInformationRepository.get(releaseInformationId);
return response;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.releaseInformationRetrievalFailed);
}
}

/**
* リリース情報を全件取得する。
* @returns 全てのリリース情報。
*/
public async getAllReleaseInformation(): Promise<ReleaseInformation[]> {
const response = await this.releaseInformationRepository.getAll();
return response;
try {
const response = await this.releaseInformationRepository.getAll();
return response;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.releaseInformationRetrievalFailed);
}
}

/**
Expand All @@ -36,7 +51,13 @@ export default class ReleaseInformationGetter {
* @returns ユーザーが設定したリリースバージョン以下のリリース情報。
*/
public async getReleaseInformationBelowUserSetting(profileId: string): Promise<ReleaseInformation[]> {
const response = await this.releaseInformationRepository.getBelowUserSetting(profileId);
return response;
try {
const response = await this.releaseInformationRepository.getBelowUserSetting(profileId);
return response;
} catch (error) {
console.error(error);
if (error instanceof TypeError) throw new Error(systemMessages.error.networkError);
throw new Error(systemMessages.error.releaseInformationRetrievalFailed);
}
}
}
Loading