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.
357 lines
11 KiB
357 lines
11 KiB
/**
|
|
* APIサービス
|
|
* バックエンドAPIとの通信を担当するモジュール
|
|
* 認証、タスク管理などの機能を提供
|
|
*/
|
|
import { LoginCredentials, RegisterCredentials, AuthResponse, Task, ToBuy, Stuff, Stock } from '../types/types';
|
|
import { AUTH_ERRORS, TASK_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_array": ToBuy[] }> => {
|
|
// const response = await fetch(`${API_BASE_URL}/api/tobuy/get`, {
|
|
// headers: getHeaders(), // 認証トークンを含むヘッダー
|
|
// });
|
|
|
|
// if (!response.ok) {
|
|
// throw new Error(TASK_ERRORS.FETCH_FAILED);
|
|
// }
|
|
|
|
// return response.json();
|
|
|
|
return {
|
|
"tobuy_array": [
|
|
{
|
|
"tobuy_id": 1,
|
|
"stuff_id": 2,
|
|
"stuff_name": "じゃがいも",
|
|
"amount": 3,
|
|
"shop": "shopXXX"
|
|
},
|
|
{
|
|
"tobuy_id": 2,
|
|
"stuff_id": 5,
|
|
"stuff_name": "にんじん",
|
|
"amount": 1
|
|
}
|
|
]
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
* 買うものリストへの材料追加
|
|
* @param tobuy 作成する材料情報
|
|
* @returns 作成された材料情報
|
|
*/
|
|
addToBuy: async (tobuy: Omit<ToBuy, 'stuff_id' | 'tobuy_id'> & { stuff_id: number | null, category: string }): Promise<any> => {
|
|
// const response = await fetch(`${API_BASE_URL}/api/tasks`, {
|
|
// method: 'POST',
|
|
// headers: getHeaders(),
|
|
// body: JSON.stringify(tobuy),
|
|
// });
|
|
|
|
// if (!response.ok) {
|
|
// throw new Error(TASK_ERRORS.CREATE_FAILED);
|
|
// }
|
|
|
|
// return response.json();
|
|
|
|
return {
|
|
"result": true,
|
|
"tobuy_id": 1,
|
|
"stuff_id": 6,
|
|
"message": "追加に成功しました",
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
* 買うものリストを削除
|
|
* @param id 削除対象の買うものリストID
|
|
*/
|
|
deleteToBuy: async (tobuy_id: number): Promise<{ result: boolean }> => {
|
|
// const response = await fetch(`${API_BASE_URL}/api/tobuy/delete`, {
|
|
// method: 'DELETE',
|
|
// headers: getHeaders(),
|
|
// body: JSON.stringify({tobuy_id}),
|
|
// });
|
|
|
|
// if (!response.ok) {
|
|
// throw new Error(TASK_ERRORS.DELETE_FAILED);
|
|
// }
|
|
|
|
return {
|
|
"result": true
|
|
}
|
|
},
|
|
}
|
|
|
|
export const stuffApi = {
|
|
getStuffs: async (category: string): Promise<{ stuff_array: Stuff[] }> => {
|
|
const data = [
|
|
{ "stuff_id": 1, "stuff_name": "牛乳", "category": "乳製品" },
|
|
{ "stuff_id": 2, "stuff_name": "ヨーグルト", "category": "乳製品" },
|
|
{ "stuff_id": 3, "stuff_name": "チーズ", "category": "乳製品" },
|
|
{ "stuff_id": 4, "stuff_name": "バター", "category": "乳製品" },
|
|
{ "stuff_id": 5, "stuff_name": "生クリーム", "category": "乳製品" },
|
|
|
|
{ "stuff_id": 6, "stuff_name": "鮭", "category": "魚・肉" },
|
|
{ "stuff_id": 7, "stuff_name": "鶏むね肉", "category": "魚・肉" },
|
|
{ "stuff_id": 8, "stuff_name": "豚バラ肉", "category": "魚・肉" },
|
|
{ "stuff_id": 9, "stuff_name": "牛ひき肉", "category": "魚・肉" },
|
|
{ "stuff_id": 10, "stuff_name": "まぐろ", "category": "魚・肉" },
|
|
|
|
{ "stuff_id": 11, "stuff_name": "にんじん", "category": "野菜" },
|
|
{ "stuff_id": 12, "stuff_name": "キャベツ", "category": "野菜" },
|
|
{ "stuff_id": 13, "stuff_name": "ほうれん草", "category": "野菜" },
|
|
{ "stuff_id": 14, "stuff_name": "玉ねぎ", "category": "野菜" },
|
|
{ "stuff_id": 15, "stuff_name": "ピーマン", "category": "野菜" },
|
|
|
|
{ "stuff_id": 16, "stuff_name": "醤油", "category": "調味料" },
|
|
{ "stuff_id": 17, "stuff_name": "味噌", "category": "調味料" },
|
|
{ "stuff_id": 18, "stuff_name": "塩", "category": "調味料" },
|
|
{ "stuff_id": 19, "stuff_name": "砂糖", "category": "調味料" },
|
|
{ "stuff_id": 20, "stuff_name": "酢", "category": "調味料" },
|
|
|
|
{ "stuff_id": 21, "stuff_name": "米", "category": "その他" },
|
|
{ "stuff_id": 22, "stuff_name": "パスタ", "category": "その他" },
|
|
{ "stuff_id": 23, "stuff_name": "小麦粉", "category": "その他" },
|
|
{ "stuff_id": 24, "stuff_name": "卵", "category": "その他" },
|
|
{ "stuff_id": 25, "stuff_name": "豆腐", "category": "その他" }
|
|
]
|
|
|
|
const filtered = data.filter(stuff => stuff.category == category)
|
|
|
|
return {
|
|
"stuff_array": filtered
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
export const stockApi = {
|
|
/**
|
|
* 全在庫リストを取得
|
|
* @returns 買在庫リスト一覧
|
|
*/
|
|
getStocks: async (): Promise<{ "stock_array": Stock[] }> => {
|
|
// const response = await fetch(`${API_BASE_URL}/api/tobuy/get`, {
|
|
// headers: getHeaders(), // 認証トークンを含むヘッダー
|
|
// });
|
|
|
|
// if (!response.ok) {
|
|
// throw new Error(TASK_ERRORS.FETCH_FAILED);
|
|
// }
|
|
|
|
// return response.json();
|
|
|
|
return {
|
|
"stock_array": [
|
|
{
|
|
"stock_id": 1,
|
|
"stuff_id": 10,
|
|
"stuff_name": "豚肉",
|
|
"amount": 100,
|
|
"price": 200,
|
|
"buy_date": "2025-05-18T09:00:00.000Z",
|
|
"last_update": "2025-05-18T09:00:00.000Z",
|
|
"exp_date": "2025-05-19T10:15:00.000Z",
|
|
"category": "肉"
|
|
},
|
|
{
|
|
"stock_id": 2,
|
|
"stuff_id": 1,
|
|
"stuff_name": "トマト",
|
|
"amount": 10,
|
|
"price": 200,
|
|
"buy_date": "2025-05-18T09:00:00.000Z",
|
|
"last_update": "2025-05-18T09:00:00.000Z",
|
|
"exp_date": "2025-05-19T10:15:00.000Z",
|
|
"category": "野菜"
|
|
}
|
|
]
|
|
}
|
|
|
|
|
|
},
|
|
}
|
|
|
|
|
|
/**
|
|
* (サンプル,実際には不要)
|
|
* タスク管理関連の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);
|
|
}
|
|
},
|
|
};
|
|
|