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.

259 lines
6.2KB

  1. import { AxiosError, AxiosResponse } from "axios";
  2. import { format } from "date-fns";
  3. import { Dictionary, get } from "lodash";
  4. import { DataUrl } from "@types";
  5. import { setFormErrorMessages } from "components/hook-form";
  6. import axios from "utils/axios";
  7. let id = 0;
  8. export const ApiId = {
  9. // 共通---------------------------------------
  10. CSRF_TOKEN: id++,
  11. ME: id++,
  12. LOGIN: id++,
  13. LOGOUT: id++,
  14. SEASON_TICKET_CONTRACTS: id++,
  15. PAYMENT_PLANS: id++,
  16. } as const;
  17. export type ApiId = (typeof ApiId)[keyof typeof ApiId];
  18. export const HttpMethod = {
  19. GET: "get",
  20. POST: "post",
  21. } as const;
  22. export type HttpMethod = (typeof HttpMethod)[keyof typeof HttpMethod];
  23. export const ResultCode = {
  24. SUCCESS: 0,
  25. FAILED: 1,
  26. UNAUTHORIZED: 2,
  27. EXCLUSIVE_ERROR: 3,
  28. };
  29. export type ResultCode = (typeof ResultCode)[keyof typeof ResultCode];
  30. export interface TimestampRequest {
  31. timestamp: string;
  32. }
  33. export type ListRequest = {
  34. sort?: string;
  35. order?: string;
  36. };
  37. export interface APICommonResponse {
  38. result: ResultCode;
  39. messages: {
  40. errors?: Dictionary<string>;
  41. general?: string;
  42. email_id?: number;
  43. };
  44. }
  45. export type ImagesResponse = {
  46. data: {
  47. images: DataUrl[];
  48. };
  49. } & APICommonResponse;
  50. export const makeParam = <T extends object>(data: T): Dictionary<string> => {
  51. const res: Dictionary<string> = {};
  52. Object.keys(data).map((key) => {
  53. const val = get(data, key);
  54. if (typeof val === "string" && val.length !== 0) {
  55. res[key] = val;
  56. } else if (typeof val === "number") {
  57. res[key] = String(val);
  58. } else if (typeof val === "boolean") {
  59. res[key] = val ? "1" : "0";
  60. } else if (val instanceof Date) {
  61. res[key] = format(val, "yyyy-MM-dd");
  62. }
  63. });
  64. return res;
  65. };
  66. export const makeFormData = <T extends object>(data: T): FormData => {
  67. const res = new FormData();
  68. Object.keys(data).map((key) => {
  69. const val = get(data, key);
  70. if (typeof val === "string" && val.length !== 0) {
  71. res.append(key, val);
  72. } else if (typeof val === "number") {
  73. res.append(key, String(val));
  74. } else if (typeof val === "boolean") {
  75. res.append(key, val ? "1" : "0");
  76. } else if (val instanceof Date) {
  77. res.append(key, format(val, "yyyy-MM-dd"));
  78. } else if (val instanceof File) {
  79. res.append(key, val);
  80. } else if (Array.isArray(val)) {
  81. val.forEach((v) => {
  82. res.append(key + "[]", v);
  83. });
  84. } else {
  85. console.log("undefined data", key, val);
  86. }
  87. });
  88. return res;
  89. };
  90. const isAxiosError = (error: any): error is AxiosError => {
  91. return !!error.isAxiosError;
  92. };
  93. type RequestArgument = {
  94. url: string;
  95. method: HttpMethod;
  96. data?: URLSearchParams | FormData | object;
  97. multipart?: boolean;
  98. };
  99. export const request = async <T extends APICommonResponse>({
  100. url,
  101. method,
  102. data,
  103. multipart,
  104. }: RequestArgument): Promise<T | null> => {
  105. let response: AxiosResponse<T | any> | null = null;
  106. if (data instanceof URLSearchParams) {
  107. data.sort();
  108. }
  109. try {
  110. if (multipart && data instanceof FormData) {
  111. response = await axios({
  112. url,
  113. method: "post",
  114. data,
  115. headers: {
  116. "content-type": "multipart/form-data",
  117. },
  118. });
  119. console.log("RESPONSE", url, "multipart", data, response?.data);
  120. } else if (method === HttpMethod.GET) {
  121. let searchUrl = url;
  122. if (data instanceof URLSearchParams) {
  123. searchUrl += "?" + data.toString();
  124. }
  125. response = await axios.get<T>(searchUrl);
  126. console.log(new Date(), "RESPONSE", searchUrl, method, response?.data);
  127. } else if (method === HttpMethod.POST) {
  128. response = await axios.post<T>(url, data);
  129. let sendData: Dictionary<String> = {};
  130. if (data instanceof URLSearchParams) {
  131. data.forEach((val, key) => {
  132. sendData[key] = val;
  133. });
  134. } else if (typeof data === "object" && !(data instanceof FormData)) {
  135. Object.keys(data).forEach((key) => {
  136. sendData[key] = get(data, key);
  137. });
  138. }
  139. console.log("RESPONSE", url, method, sendData, response?.data);
  140. } else {
  141. return null;
  142. }
  143. if (response && response.data.result === ResultCode.SUCCESS) {
  144. return response.data;
  145. }
  146. return response?.data;
  147. } catch (e) {
  148. if (isAxiosError(e)) {
  149. if (e.response?.status === 401 || e.response?.status === 419) {
  150. window.location.reload();
  151. }
  152. }
  153. if (typeof e === "object") {
  154. const message = get(e, "message");
  155. if (message === "Unauthenticated.") {
  156. console.log("401!!!");
  157. window.location.reload();
  158. return null;
  159. }
  160. if (message === "CSRF token mismatch.") {
  161. console.log("419!!!");
  162. window.location.reload();
  163. return null;
  164. }
  165. if (message === "Service Unavailable") {
  166. console.log("503!!!");
  167. window.location.reload();
  168. return null;
  169. }
  170. }
  171. throw e;
  172. }
  173. };
  174. export async function apiRequest<
  175. T extends APICommonResponse,
  176. U extends object
  177. >({
  178. apiMethod,
  179. sendData,
  180. onSuccess,
  181. onFailed,
  182. onFinaly,
  183. errorSetter,
  184. setSending,
  185. }: {
  186. apiMethod: (sendData: U) => Promise<T | null>;
  187. sendData: U;
  188. onSuccess?: (res: T, sendData: U) => void;
  189. onFailed?: (res: APICommonResponse | null) => void;
  190. onFinaly?: (res: APICommonResponse | null) => void;
  191. errorSetter?: any;
  192. setSending?: (sending: boolean) => void;
  193. }) {
  194. if (setSending) {
  195. setSending(true);
  196. }
  197. try {
  198. const res = await apiMethod(sendData);
  199. if (setSending) {
  200. setSending(false);
  201. }
  202. if (res?.result === ResultCode.SUCCESS) {
  203. if (onSuccess) {
  204. onSuccess(res, sendData);
  205. }
  206. } else {
  207. if (res?.messages.errors) {
  208. if (errorSetter) {
  209. const errorCount = setFormErrorMessages(
  210. sendData,
  211. errorSetter,
  212. res.messages.errors
  213. );
  214. console.log("FormErrorCount", errorCount);
  215. }
  216. }
  217. if (onFailed) {
  218. onFailed(res);
  219. }
  220. if (onFinaly) {
  221. onFinaly(res);
  222. }
  223. }
  224. return res;
  225. } catch (e) {
  226. if (setSending) {
  227. setSending(false);
  228. }
  229. console.error(e);
  230. if (onFailed) {
  231. onFailed(null);
  232. }
  233. if (onFinaly) {
  234. onFinaly(null);
  235. }
  236. return null;
  237. }
  238. }