Skip to content

Commit

Permalink
Merge pull request #90 from Mouwf/feature/add-display-error-message-f…
Browse files Browse the repository at this point in the history
…unction

システムメッセージを表示する機能を追加した
  • Loading branch information
eigoninaritai-naokichi authored Feb 18, 2024
2 parents 72f368c + 67ac51a commit d9fa1b2
Show file tree
Hide file tree
Showing 75 changed files with 1,287 additions and 1,070 deletions.
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

0 comments on commit d9fa1b2

Please sign in to comment.