@obb871001/api-integration-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/index.cjs +1 -0
- package/dist/index.js +3 -0
- package/dist/vite.svg +1 -0
- package/package.json +72 -0
- package/src/App.css +42 -0
- package/src/App.jsx +7 -0
- package/src/api/client.js +59 -0
- package/src/function/usePeriodicDataUpdater.js +19 -0
- package/src/hooks/useAxios.js +10 -0
- package/src/index.css +68 -0
- package/src/index.js +1 -0
- package/src/main.jsx +10 -0
- package/src/provider.jsx +15 -0
- package/src/services/index.js +2 -0
- package/src/services/useCommonApi.jsx +28 -0
- package/src/services/useUserApi.jsx +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# React + Vite
|
|
2
|
+
|
|
3
|
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
+
|
|
5
|
+
Currently, two official plugins are available:
|
|
6
|
+
|
|
7
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
|
8
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
9
|
+
|
|
10
|
+
## React Compiler
|
|
11
|
+
|
|
12
|
+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
|
13
|
+
|
|
14
|
+
## Expanding the ESLint configuration
|
|
15
|
+
|
|
16
|
+
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t){typeof exports=="object"&&typeof module<"u"?t(require("@tanstack/react-query"),require("react")):typeof define=="function"&&define.amd?define(["@tanstack/react-query","react"],t):(e=typeof globalThis<"u"?globalThis:e||self,t(e.ReactQuery,e.React))})(this,(function(e,t){"use strict";t.createContext(null)}));
|
package/dist/index.js
ADDED
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@obb871001/api-integration-sdk",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "集成API",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "src/index.js",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./src/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "vite",
|
|
22
|
+
"build": "vite build",
|
|
23
|
+
"build:lib": "vite build --mode lib",
|
|
24
|
+
"lint": "eslint .",
|
|
25
|
+
"preview": "vite preview",
|
|
26
|
+
"prepublishOnly": "npm run build:lib"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"api",
|
|
30
|
+
"integration",
|
|
31
|
+
"react",
|
|
32
|
+
"react-query",
|
|
33
|
+
"tanstack-query",
|
|
34
|
+
"axios",
|
|
35
|
+
"sdk",
|
|
36
|
+
"library"
|
|
37
|
+
],
|
|
38
|
+
"author": "Your Name <your.email@example.com>",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/obb871001/api-integration-sdk.git"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/obb871001/api-integration-sdk#readme",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/obb871001/api-integration-sdk/issues"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"react": ">=16.8.0",
|
|
50
|
+
"react-dom": ">=16.8.0",
|
|
51
|
+
"@tanstack/react-query": ">=4.0.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"axios": "^1.12.2",
|
|
55
|
+
"lodash": "^4.17.21"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@eslint/js": "^9.36.0",
|
|
59
|
+
"@tanstack/react-query": "^5.90.5",
|
|
60
|
+
"@tanstack/react-query-devtools": "^5.90.2",
|
|
61
|
+
"@types/react": "^19.1.16",
|
|
62
|
+
"@types/react-dom": "^19.1.9",
|
|
63
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
64
|
+
"eslint": "^9.36.0",
|
|
65
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
66
|
+
"eslint-plugin-react-refresh": "^0.4.22",
|
|
67
|
+
"globals": "^16.4.0",
|
|
68
|
+
"react": "^19.1.1",
|
|
69
|
+
"react-dom": "^19.1.1",
|
|
70
|
+
"vite": "^7.1.7"
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/App.css
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#root {
|
|
2
|
+
max-width: 1280px;
|
|
3
|
+
margin: 0 auto;
|
|
4
|
+
padding: 2rem;
|
|
5
|
+
text-align: center;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.logo {
|
|
9
|
+
height: 6em;
|
|
10
|
+
padding: 1.5em;
|
|
11
|
+
will-change: filter;
|
|
12
|
+
transition: filter 300ms;
|
|
13
|
+
}
|
|
14
|
+
.logo:hover {
|
|
15
|
+
filter: drop-shadow(0 0 2em #646cffaa);
|
|
16
|
+
}
|
|
17
|
+
.logo.react:hover {
|
|
18
|
+
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@keyframes logo-spin {
|
|
22
|
+
from {
|
|
23
|
+
transform: rotate(0deg);
|
|
24
|
+
}
|
|
25
|
+
to {
|
|
26
|
+
transform: rotate(360deg);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
31
|
+
a:nth-of-type(2) .logo {
|
|
32
|
+
animation: logo-spin infinite 20s linear;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.card {
|
|
37
|
+
padding: 2em;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.read-the-docs {
|
|
41
|
+
color: #888;
|
|
42
|
+
}
|
package/src/App.jsx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 建立 axios instance(可選擇性注入 getToken / 其他攔截器)
|
|
5
|
+
* @param {Object} options
|
|
6
|
+
* @param {string} options.baseURL
|
|
7
|
+
* @param {() => (string|undefined|Promise<string|undefined>)} [options.getToken]
|
|
8
|
+
* @param {number} [options.timeoutMs=15000]
|
|
9
|
+
* @param {import('axios').AxiosInstance} [options.axiosInstance] - 若有外部共用 instance,可直接注入
|
|
10
|
+
* @param {string} [options.currency] - 預設貨幣代碼(可用於自訂攔截器)
|
|
11
|
+
* @param {string} [options.lng] - 預設語言代碼(可用於自訂攔截器)
|
|
12
|
+
* @param {(error:any, ctx:{instance:any}) => any} [options.onError] - 統一錯誤處理(可回傳 Promise.reject(error))
|
|
13
|
+
* @returns {import('axios').AxiosInstance}
|
|
14
|
+
*/
|
|
15
|
+
export function createAxiosClient({
|
|
16
|
+
baseURL,
|
|
17
|
+
getToken,
|
|
18
|
+
timeoutMs = 15000,
|
|
19
|
+
axiosInstance,
|
|
20
|
+
currency,
|
|
21
|
+
lng,
|
|
22
|
+
onError,
|
|
23
|
+
} = {}) {
|
|
24
|
+
const instance =
|
|
25
|
+
axiosInstance ??
|
|
26
|
+
axios.create({
|
|
27
|
+
baseURL: baseURL,
|
|
28
|
+
timeout: timeoutMs,
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
instance.interceptors.request.use(async (config) => {
|
|
33
|
+
if (getToken) {
|
|
34
|
+
const token = await getToken();
|
|
35
|
+
if (token) {
|
|
36
|
+
config.headers = config.headers || {};
|
|
37
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return config;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
instance.interceptors.request.use((config) => {
|
|
44
|
+
config.headers.Currency = currency;
|
|
45
|
+
config.headers[`currency-code`] = currency;
|
|
46
|
+
config.headers[`lang`] = lng;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Response: 統一錯誤處理(交由外部決定)
|
|
50
|
+
instance.interceptors.response.use(
|
|
51
|
+
(res) => res,
|
|
52
|
+
(err) => {
|
|
53
|
+
if (onError) return onError(err, { instance });
|
|
54
|
+
return Promise.reject(err);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return instance;
|
|
59
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useQueries } from "@tanstack/react-query";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import useUserApi from "../services/useUserApi";
|
|
4
|
+
|
|
5
|
+
const usePeriodicDataUpdater = () => {
|
|
6
|
+
const { userInfoApi } = useUserApi();
|
|
7
|
+
const { data, isFetching } = useQueries({
|
|
8
|
+
queries: [
|
|
9
|
+
{
|
|
10
|
+
queryKey: ["getMemberInfo"],
|
|
11
|
+
queryFn: userInfoApi,
|
|
12
|
+
refetchInterval: 50000,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
});
|
|
16
|
+
return { data, isFetching };
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default usePeriodicDataUpdater;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React, { createContext, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
const ApiCtx = createContext(null);
|
|
4
|
+
|
|
5
|
+
export const useAxios = () => {
|
|
6
|
+
const ctx = useContext(ApiCtx);
|
|
7
|
+
|
|
8
|
+
if (!ctx) throw new Error("useAxios must be used inside <ApiProvider>");
|
|
9
|
+
return ctx.client;
|
|
10
|
+
};
|
package/src/index.css
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
color: rgba(255, 255, 255, 0.87);
|
|
8
|
+
background-color: #242424;
|
|
9
|
+
|
|
10
|
+
font-synthesis: none;
|
|
11
|
+
text-rendering: optimizeLegibility;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
a {
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
color: #646cff;
|
|
19
|
+
text-decoration: inherit;
|
|
20
|
+
}
|
|
21
|
+
a:hover {
|
|
22
|
+
color: #535bf2;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
display: flex;
|
|
28
|
+
place-items: center;
|
|
29
|
+
min-width: 320px;
|
|
30
|
+
min-height: 100vh;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
h1 {
|
|
34
|
+
font-size: 3.2em;
|
|
35
|
+
line-height: 1.1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
button {
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
border: 1px solid transparent;
|
|
41
|
+
padding: 0.6em 1.2em;
|
|
42
|
+
font-size: 1em;
|
|
43
|
+
font-weight: 500;
|
|
44
|
+
font-family: inherit;
|
|
45
|
+
background-color: #1a1a1a;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
transition: border-color 0.25s;
|
|
48
|
+
}
|
|
49
|
+
button:hover {
|
|
50
|
+
border-color: #646cff;
|
|
51
|
+
}
|
|
52
|
+
button:focus,
|
|
53
|
+
button:focus-visible {
|
|
54
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@media (prefers-color-scheme: light) {
|
|
58
|
+
:root {
|
|
59
|
+
color: #213547;
|
|
60
|
+
background-color: #ffffff;
|
|
61
|
+
}
|
|
62
|
+
a:hover {
|
|
63
|
+
color: #747bff;
|
|
64
|
+
}
|
|
65
|
+
button {
|
|
66
|
+
background-color: #f9f9f9;
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./function/usePeriodicDataUpdater";
|
package/src/main.jsx
ADDED
package/src/provider.jsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { createAxiosClient } from "./api/client";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ApiProvider props:
|
|
6
|
+
* - baseURL: string
|
|
7
|
+
* - getToken?: () => string | undefined | Promise<string | undefined>
|
|
8
|
+
* - timeoutMs?: number
|
|
9
|
+
* - axiosInstance?: AxiosInstance // 注入你自己的 axios(可共用攔截器)
|
|
10
|
+
* - onError?: (error, ctx) => any // 全域錯誤處理
|
|
11
|
+
*/
|
|
12
|
+
export function ApiProvider({ children, ...opts }) {
|
|
13
|
+
const client = useMemo(() => createAxiosClient(opts), [opts]);
|
|
14
|
+
return <ApiCtx.Provider value={{ client }}>{children}</ApiCtx.Provider>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import { useAxios } from "../hooks/useAxios";
|
|
3
|
+
|
|
4
|
+
const useCommonApi = () => {
|
|
5
|
+
const axios = useAxios();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @description 取得輪播圖資訊
|
|
9
|
+
* @return {Promise<Object>} 輪播圖資訊
|
|
10
|
+
*/
|
|
11
|
+
const carouselApi = useCallback(async () => {
|
|
12
|
+
const { data } = await axios.get("/carousels");
|
|
13
|
+
return data;
|
|
14
|
+
}, [axios]);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @description 取得跑馬燈資訊
|
|
18
|
+
* @return {Promise<Object>} 跑馬燈資訊
|
|
19
|
+
*/
|
|
20
|
+
const marqueeApi = useCallback(async () => {
|
|
21
|
+
const { data } = await axios.get("/marquees");
|
|
22
|
+
return data;
|
|
23
|
+
}, [axios]);
|
|
24
|
+
|
|
25
|
+
return { carouselApi, marqueeApi };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default useCommonApi;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import { useAxios } from "../hooks/useAxios";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description 使用者相關 API
|
|
6
|
+
* @returns {Object} API 方法集合
|
|
7
|
+
* @property {Function} machineLoginApi 機台登入 API
|
|
8
|
+
* @property {Function} userInfoApi 取得使用者資訊 API
|
|
9
|
+
*/
|
|
10
|
+
const useUserApi = () => {
|
|
11
|
+
const axios = useAxios();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @description 機台登入
|
|
15
|
+
* @param {Object} params
|
|
16
|
+
* @param {string} params.mac_address 機台 MAC 地址
|
|
17
|
+
* @param {string} params.app_version 應用程式版本
|
|
18
|
+
* @param {string} params.anydesk_id 遠端協助軟體 ID
|
|
19
|
+
*/
|
|
20
|
+
const machineLoginApi = useCallback(
|
|
21
|
+
async (params) => {
|
|
22
|
+
const { mac_address = "", app_version = "", anydesk_id = "" } = params;
|
|
23
|
+
const { data } = await axios.post("/cash-register/login", {
|
|
24
|
+
mac_address,
|
|
25
|
+
app_version,
|
|
26
|
+
anydesk_id,
|
|
27
|
+
});
|
|
28
|
+
return data;
|
|
29
|
+
},
|
|
30
|
+
[axios]
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @description 取得使用者資訊
|
|
35
|
+
* @return {Promise<Object>} 使用者資訊
|
|
36
|
+
*/
|
|
37
|
+
const userInfoApi = useCallback(async () => {
|
|
38
|
+
const { data } = await axios.get("/getMemberInfo");
|
|
39
|
+
return data;
|
|
40
|
+
}, [axios]);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @description 取得使用者遊戲列表
|
|
44
|
+
* @return {Promise<Object>} 使用者遊戲列表
|
|
45
|
+
*/
|
|
46
|
+
const userGameListApi = useCallback(async () => {
|
|
47
|
+
const { data } = await axios.get("/getGameList");
|
|
48
|
+
return data;
|
|
49
|
+
}, [axios]);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @description 取得即時匯率資訊
|
|
53
|
+
* @return {Promise<Object>} 即時匯率資訊
|
|
54
|
+
*/
|
|
55
|
+
const userCurrencyExchangeApi = useCallback(async () => {
|
|
56
|
+
const { data } = await axios.get("/getNowCurrencyExchange");
|
|
57
|
+
return data;
|
|
58
|
+
}, [axios]);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @description 取得使用者最愛遊戲列表
|
|
62
|
+
* @return {Promise<Object>} 使用者最愛遊戲列表
|
|
63
|
+
*/
|
|
64
|
+
const userFavoriteGameApi = useCallback(async () => {
|
|
65
|
+
const { data } = await axios.get("/getFavoriteGame");
|
|
66
|
+
return data;
|
|
67
|
+
}, [axios]);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
machineLoginApi,
|
|
71
|
+
userInfoApi,
|
|
72
|
+
userGameListApi,
|
|
73
|
+
userFavoriteGameApi,
|
|
74
|
+
userCurrencyExchangeApi,
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export default useUserApi;
|