You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
joint_exc/frontend/src/services/api.ts

422 lines
13 KiB

/**
* APIサービス
* バックエンドAPIとの通信を担当するモジュール
* 認証、タスク管理などの機能を提供
*/
import { LoginCredentials, RegisterCredentials, AuthResponse, /* Task, */ ToBuy, Stuff, Stock } from '../types/types';
import { AUTH_ERRORS, TOBUY_ERRORS, STOCK_ERRORS } from '../constants/errorMessages';
// APIのベースURL - 環境変数から取得するか、デフォルト値を使用
const API_BASE_URL = process.env.REACT_APP_API_BASE_URL || 'http://localhost:8080';
/**
* APIリクエスト用のヘッダーを生成する関数
* @param includeAuth 認証トークンをヘッダーに含めるかどうか
* @returns リクエストヘッダーオブジェクト
*/
const getHeaders = (includeAuth: boolean = true) => {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// 認証トークンが必要な場合はローカルストレージから取得してヘッダーに追加
if (includeAuth) {
const token = localStorage.getItem('token');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
}
return headers;
};
/**
* 認証関連のAPI機能を提供するオブジェクト
* ログインと新規ユーザー登録の機能を含む
*/
export const authApi = {
/**
* ユーザーログイン処理
* @param credentials ログイン情報(ユーザー名とパスワード)
* @returns 認証レスポンス(トークンとユーザー情報)
*/
login: async (credentials: LoginCredentials): Promise<AuthResponse> => {
const response = await fetch(`${API_BASE_URL}/api/auth/login`, {
method: 'POST',
headers: getHeaders(false), // 認証前なのでトークンは不要
body: JSON.stringify(credentials),
});
// エラーレスポンスの処理
if (!response.ok) {
const errorData = await response.json().catch(() => null);
throw new Error(
errorData?.message || AUTH_ERRORS.LOGIN_FAILED
);
}
return response.json();
},
/**
* 新規ユーザー登録処理
* @param credentials 登録情報(ユーザー名、パスワード)
* @returns 認証レスポンス(トークンとユーザー情報)
*/
register: async (credentials: RegisterCredentials): Promise<AuthResponse> => {
const response = await fetch(`${API_BASE_URL}/api/auth/register`, {
method: 'POST',
headers: getHeaders(false), // 認証前なのでトークンは不要
body: JSON.stringify(credentials),
});
// エラーレスポンスの処理
if (!response.ok) {
const errorData = await response.json().catch(() => null);
throw new Error(
errorData?.message || AUTH_ERRORS.REGISTER_FAILED
);
}
return response.json();
},
};
/**
* 買うものリスト管理関連のAPI機能を提供するオブジェクト
* 買うものリストの取得、作成、更新、削除などの機能を含む
*/
export const toBuyApi = {
/**
* 全買うものリストを取得
* @returns 買うものリスト一覧
*/
getToBuys: async (): Promise<ToBuy[]> => {
const response = await fetch(`${API_BASE_URL}/api/tobuy/get`, {
headers: getHeaders(), // 認証トークンを含むヘッダー
});
if (!response.ok) {
throw new Error(TOBUY_ERRORS.FETCH_FAILED);
}
return await response.json();
},
/**
* 買うものリストへの材料追加
* @param tobuy 作成する材料情報
* @returns 作成された材料情報
*/
addToBuy: async (tobuy: Omit<ToBuy, 'stuffId' | 'tobuyId'> & { stuffId: number | null, category: string }): Promise<any> => {
const response = await fetch(`${API_BASE_URL}/api/tobuy/add`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(tobuy),
});
if (!response.ok) {
throw new Error(TOBUY_ERRORS.CREATE_FAILED);
}
return response.json();
// return {result: true}
// return {
// "result": true,
// "tobuyId": 1,
// "stuffId": 6,
// "message": "追加に成功しました",
// }
},
/**
* 買うものリストを削除
* @param id 削除対象の買うものリストID
*/
deleteToBuy: async (tobuyId: number): Promise<{ result: boolean }> => {
const response = await fetch(`${API_BASE_URL}/api/tobuy/delete`, {
method: 'DELETE',
headers: getHeaders(),
body: JSON.stringify({ tobuyId }),
});
if (!response.ok) {
throw new Error(TOBUY_ERRORS.DELETE_FAILED);
}
return response.json()
// return {
// "result": true
// }
},
/**
* 買うものリストの在庫登録(購入処理)
*/
buy: async (req: { tobuyId: number, price: number, expDate: string, buyDate: string, lastUpdate: string }): Promise<{ result: boolean }> => {
console.log('req: ', req)
req.buyDate = makeDateObject(req.buyDate)?.toISOString()?.substring(0, 10) || ''
req.expDate = makeDateObject(req.expDate)?.toISOString()?.substring(0, 10) || ''
const response = await fetch(`${API_BASE_URL}/api/tobuy/buy`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(req),
});
if (!response.ok) {
throw new Error(TOBUY_ERRORS.BUY_FAILED);
}
return response.json()
},
}
export const stuffApi = {
getStuffs: async (category: string): Promise<Stuff[]> => {
const data = await fetch(`${API_BASE_URL}/api/stuff/get?category=${encodeURIComponent(category)}`, {
headers: getHeaders(), // 認証トークンを含むヘッダー
});
if (!data.ok) {
throw new Error(`Failed to fetch stuffs for category ${category}`);
}
return data.json();
// const data = [
// { stuffId: 1, stuffName: "牛乳", category: "乳製品" },
// { stuffId: 2, stuffName: "ヨーグルト", category: "乳製品" },
// { stuffId: 3, stuffName: "チーズ", category: "乳製品" },
// { stuffId: 4, stuffName: "バター", category: "乳製品" },
// { stuffId: 5, stuffName: "生クリーム", category: "乳製品" },
// { stuffId: 6, stuffName: "鮭", category: "魚・肉" },
// { stuffId: 7, stuffName: "鶏むね肉", category: "魚・肉" },
// { stuffId: 8, stuffName: "豚バラ肉", category: "魚・肉" },
// { stuffId: 9, stuffName: "牛ひき肉", category: "魚・肉" },
// { stuffId: 10, stuffName: "まぐろ", category: "魚・肉" },
// { stuffId: 11, stuffName: "にんじん", category: "野菜" },
// { stuffId: 12, stuffName: "キャベツ", category: "野菜" },
// { stuffId: 13, stuffName: "ほうれん草", category: "野菜" },
// { stuffId: 14, stuffName: "玉ねぎ", category: "野菜" },
// { stuffId: 15, stuffName: "ピーマン", category: "野菜" },
// { stuffId: 16, stuffName: "醤油", category: "調味料" },
// { stuffId: 17, stuffName: "味噌", category: "調味料" },
// { stuffId: 18, stuffName: "塩", category: "調味料" },
// { stuffId: 19, stuffName: "砂糖", category: "調味料" },
// { stuffId: 20, stuffName: "酢", category: "調味料" },
// { stuffId: 21, stuffName: "米", category: "その他" },
// { stuffId: 22, stuffName: "パスタ", category: "その他" },
// { stuffId: 23, stuffName: "小麦粉", category: "その他" },
// { stuffId: 24, stuffName: "卵", category: "その他" },
// { stuffId: 25, stuffName: "豆腐", category: "その他" }
// ]
// const filtered = data.filter(stuff => stuff.category == category)
// return filtered
}
}
export const stockApi = {
/**
* 全在庫リストを取得
* @returns 買在庫リスト一覧
*/
getStocks: async (): Promise<Stock[]> => {
const response = await fetch(`${API_BASE_URL}/api/stocks/get`, {
headers: getHeaders(), // 認証トークンを含むヘッダー
});
if (!response.ok) {
throw new Error(STOCK_ERRORS.FETCH_FAILED);
}
return response.json();
},
/**
* 在庫リストの編集
*/
updateStock: async (req: {stockId: number, amount: number, price: number, lastUpdate: string, buyDate: string, expDate: string}): Promise<{ result: boolean; message: string }> => {
const response = await fetch(`${API_BASE_URL}/api/stocks/update`, {
method: 'PUT',
headers: getHeaders(),
body: JSON.stringify(req),
});
if (!response.ok) {
throw new Error(STOCK_ERRORS.UPDATE_FAILED);
}
return response.json()
// return {
// "result": true
// }
},
/**
* 在庫リストの削除
* @param id 削除対象の食材のID
*/
deleteStock: async (stockId: number): Promise<{ result: boolean; message: string }> => {
const response = await fetch(`${API_BASE_URL}/api/stocks/delete`, {
method: 'DELETE',
headers: getHeaders(),
body: JSON.stringify({ stockId }),
});
console.log("API レスポンスステータス:", response.status);
console.log("API レスポンス本文:", await response.text());
if (!response.ok) {
throw new Error(STOCK_ERRORS.DELETE_FAILED);
}
return response.json()
// return {
// "result": true
// }
},
}
const deleteStock = async (stockId: number): Promise<{ result: boolean; message: string }> => {
console.log("API の deleteStock メソッドが呼ばれました。stockId:", stockId);
const response = await fetch(`${API_BASE_URL}/api/stocks/delete`, {
method: "DELETE",
headers: getHeaders(),
body: JSON.stringify({ stockId }),
});
console.log("API レスポンスステータス:", response.status);
console.log("API レスポンス本文:", await response.text());
if (!response.ok) {
return { result: false, message: "削除に失敗しました。" };
}
// API のレスポンスから result と message を取得
const data = await response.json();
return { result: data.result, message: data.message };
};
function makeDateObject(dateStr: String) {
// 例: '2025/06/15' または '2025-06-15' を '2025-06-15' に変換
const parts = dateStr.split(/[-\/]/); // ハイフンかスラッシュで分割
if (parts.length === 3) {
return new Date(parts[0] + '-' + parts[1] + '-' + parts[2]);
}
return null; // 無効な日付の場合
}
// /**
// * (サンプル,実際には不要)
// * タスク管理関連のAPI機能を提供するオブジェクト
// * タスクの取得、作成、更新、削除などの機能を含む
// */
// export const taskApi = {
// /**
// * 全タスクを取得
// * @returns タスク一覧
// */
// getTasks: async (): Promise<Task[]> => {
// const response = await fetch(`${API_BASE_URL}/api/tasks`, {
// headers: getHeaders(), // 認証トークンを含むヘッダー
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.FETCH_FAILED);
// }
// return response.json();
// },
// /**
// * 指定IDのタスクを取得
// * @param id タスクID
// * @returns 単一のタスク情報
// */
// getTask: async (id: number): Promise<Task> => {
// const response = await fetch(`${API_BASE_URL}/api/tasks/${id}`, {
// headers: getHeaders(),
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.FETCH_FAILED);
// }
// return response.json();
// },
// /**
// * 新規材料を作成
// * @param task 作成するタスク情報(価格,作成日時、更新日時は除外)
// * @returns 作成されたタスク情報
// */
// addStuff: async (task: Omit<Task, 'userId' | 'createdAt' | 'price' | 'buyDate' | 'expirationDate' | 'newAddition'>): Promise<Task> => {
// const response = await fetch(`${API_BASE_URL}/api/tubuy/add`, {
// method: 'POST',
// headers: getHeaders(),
// body: JSON.stringify(task),
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.CREATE_FAILED);
// }
// return response.json();
// },
// /**
// * タスクを更新
// * @param id 更新対象のタスクID
// * @param task 更新するタスク情報(部分的な更新も可能)
// * @returns 更新後のタスク情報
// */
// updateTask: async (id: number, task: Partial<Task>): Promise<Task> => {
// const response = await fetch(`${API_BASE_URL}/api/tasks/${id}`, {
// method: 'PUT',
// headers: getHeaders(),
// body: JSON.stringify(task),
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.UPDATE_FAILED);
// }
// return response.json();
// },
// /**
// * タスクを削除
// * @param id 削除対象のタスクID
// */
// deleteTask: async (id: number): Promise<void> => {
// const response = await fetch(`${API_BASE_URL}/api/tasks/${id}`, {
// method: 'DELETE',
// headers: getHeaders(),
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.DELETE_FAILED);
// }
// },
// };