Last active
February 15, 2025 04:39
-
-
Save tbxark/adbe65da6d49605f81d4a33f57f163f5 to your computer and use it in GitHub Desktop.
Sphere Dash Adapter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Api } from "@/api/dash/Api"; | |
| import { http } from "@/utils/http"; | |
| import type { AxiosInstance, AxiosResponse } from "axios"; | |
| import type { HttpClient } from "@/api/dash/http-client"; | |
| interface PureHTTP { | |
| axiosInstance: AxiosInstance; | |
| } | |
| type UnwrapResponse<T> = | |
| T extends Promise<AxiosResponse<infer R>> ? Promise<R> : T; | |
| type TransformFunction<T> = T extends (...args: infer Args) => infer Return | |
| ? (...args: Args) => UnwrapResponse<Return> | |
| : never; | |
| type UnwrappedApiClient = { | |
| [K in keyof Omit<Api, keyof HttpClient>]: TransformFunction<Api[K]>; | |
| }; | |
| type AdapterAPI = UnwrappedApiClient & { | |
| request: TransformFunction<Api["request"]>; | |
| }; | |
| function createNewAPI(): AdapterAPI { | |
| const api = new Api(); | |
| api.instance = (http.constructor as unknown as PureHTTP).axiosInstance; | |
| return api as AdapterAPI; | |
| } | |
| export const API = createNewAPI(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| type SnakeToCamelCase<S extends string> = S extends `${infer T}_${infer U}` | |
| ? `${T}${Capitalize<SnakeToCamelCase<U>>}` | |
| : S; | |
| type SnakeToCamelCaseObject<T> = { | |
| [K in keyof T as K extends string | |
| ? SnakeToCamelCase<K> | |
| : K]: T[K] extends object ? SnakeToCamelCaseObject<T[K]> : T[K]; | |
| }; | |
| export function convertToCamelCase<T extends object>( | |
| obj: T, | |
| ): SnakeToCamelCaseObject<T> { | |
| const toCamelCase = (str: string): string => { | |
| return str | |
| .split('_') | |
| .map((part, index) => | |
| index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1), | |
| ) | |
| .join(''); | |
| }; | |
| const result: Record<string, unknown> = {}; | |
| for (const [key, value] of Object.entries(obj)) { | |
| const camelKey = toCamelCase(key); | |
| result[camelKey] = | |
| value instanceof Object && !Array.isArray(value) | |
| ? convertToCamelCase(value) | |
| : value; | |
| } | |
| return result as SnakeToCamelCaseObject<T>; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { computed, ref, watch } from "vue"; | |
| interface ListQueryParam { | |
| page?: number; | |
| limit?: number; | |
| } | |
| export interface ListManager<QUERY, DATA> { | |
| query: ReturnType<typeof ref<QUERY>>; | |
| data: ReturnType<typeof ref<DATA>>; | |
| totalPage: ReturnType<typeof ref<number>>; | |
| displayPage: ReturnType<typeof ref<number>>; | |
| execute: (query: QUERY) => Promise<void>; | |
| onResetQuery: () => void; | |
| onSearch: () => Promise<void>; | |
| onPageChange: (val: number) => Promise<void>; | |
| } | |
| type PaginatedListData<ITEM, KEY extends string> = { | |
| [P in KEY]?: ITEM[]; | |
| } & { | |
| total?: number; | |
| total_page?: number; | |
| }; | |
| type PaginatedListItem<REQUEST, KEY extends string> = REQUEST extends ( | |
| ...args: any | |
| ) => Promise<{ data?: PaginatedListData<infer ITEM, KEY> }> | |
| ? ITEM | |
| : never; | |
| export function createListManager< | |
| KEY extends string, | |
| REQUEST extends (...args: any) => Promise<any>, | |
| ITEM = PaginatedListItem<REQUEST, KEY>, | |
| QUERY extends ListQueryParam = Parameters<REQUEST>[0], | |
| DATA extends PaginatedListData<ITEM, KEY> = PaginatedListData<ITEM, KEY> | |
| >(options: { query: QUERY; request: REQUEST }): ListManager<QUERY, DATA> { | |
| const query = ref<QUERY>(options.query); | |
| const data = ref<DATA | null>(null); | |
| const totalPage = ref(1); | |
| const displayPage = computed(() => (query.value.page || 0) + 1); | |
| watch(data, newData => { | |
| if (newData.total_page) { | |
| totalPage.value = newData.total_page; | |
| } | |
| }); | |
| const execute = async (query: QUERY) => { | |
| try { | |
| data.value = (await options.request(query)).data; | |
| } catch (e) { | |
| console.error("[ListManager] execute", e); | |
| } | |
| }; | |
| const onResetQuery = () => { | |
| query.value = {}; | |
| }; | |
| const onSearch = async () => { | |
| query.value.page = 0; | |
| await execute(query.value); | |
| }; | |
| const onPageChange = async (val: number) => { | |
| query.value.page = val - 1; | |
| await execute(query.value); | |
| }; | |
| return { | |
| query, | |
| data, | |
| totalPage, | |
| displayPage, | |
| execute, | |
| onResetQuery, | |
| onSearch, | |
| onPageChange | |
| } as ListManager<QUERY, DATA>; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment