@akanjs/next 0.0.51 → 0.0.53

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/index.js ADDED
@@ -0,0 +1,41 @@
1
+ import { useFetch } from "./useFetch";
2
+ import { lazy } from "./lazy";
3
+ import { makePageProto } from "./makePageProto";
4
+ import { useDebounce } from "./useDebounce";
5
+ import { useInterval } from "./useInterval";
6
+ import { bootCsr } from "./bootCsr";
7
+ import { useCamera } from "./useCamera";
8
+ import { useContact } from "./useContact";
9
+ import { usePushNoti } from "./usePushNoti";
10
+ import { useGeoLocation } from "./useGeoLocation";
11
+ import { useCodepush } from "./useCodepush";
12
+ import { usePurchase } from "./usePurchase";
13
+ import { useCsrValues } from "./useCsrValues";
14
+ import { createRobotPage } from "./createRobotPage";
15
+ import { createSitemapPage } from "./createSitemapPage";
16
+ import { createNextMiddleware } from "./createNextMiddleware";
17
+ //! PageAgent csr에서 말썽 일으킨다
18
+ import { useThrottle } from "./useThrottle";
19
+ import { useHistory } from "./useHistory";
20
+ import { useLocation } from "./useLocation";
21
+ export {
22
+ bootCsr,
23
+ createNextMiddleware,
24
+ createRobotPage,
25
+ createSitemapPage,
26
+ lazy,
27
+ makePageProto,
28
+ useCamera,
29
+ useCodepush,
30
+ useContact,
31
+ useCsrValues,
32
+ useDebounce,
33
+ useFetch,
34
+ useGeoLocation,
35
+ useHistory,
36
+ useInterval,
37
+ useLocation,
38
+ usePurchase,
39
+ usePushNoti,
40
+ useThrottle
41
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/next",
3
- "version": "0.0.51",
3
+ "version": "0.0.53",
4
4
  "type": "commonjs",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/bootCsr.tsx DELETED
@@ -1,180 +0,0 @@
1
- "use client";
2
- import { device, initAuth, storage } from "@akanjs/client";
3
- import {
4
- type CsrConfig,
5
- csrContext,
6
- DEFAULT_BOTTOM_INSET,
7
- DEFAULT_TOP_INSET,
8
- defaultPageState,
9
- type PageState,
10
- type PathRoute,
11
- type Route,
12
- type RouteGuide,
13
- } from "@akanjs/client";
14
- import { Logger } from "@akanjs/common";
15
- import React, { ReactNode } from "react"; // import React 꼭 필요함. 안그러면 csr에서 에러남
16
- import * as ReactDOM from "react-dom/client";
17
-
18
- import { useCsrValues } from "./useCsrValues";
19
-
20
- const supportLanguages = ["en", "ko"] as const;
21
-
22
- export const bootCsr = async (
23
- context: Record<string, () => Promise<unknown>>,
24
- rootPath: string,
25
- entryPath = "/route"
26
- ) => {
27
- // 1. Collect Device Information
28
- const [, jwt] = await Promise.all([device.init({ supportLanguages }), storage.getItem("jwt")]);
29
- if (jwt) initAuth({ jwt });
30
- Logger.verbose(`Set default language: ${device.lang}`);
31
-
32
- // 2. Create Route Map
33
- const pages: { [key: string]: { default: { csrConfig?: CsrConfig } } } = {};
34
- await Promise.all(
35
- Object.entries(context).map(async ([key, value]) => {
36
- pages[key] = (await value()) as { default: { csrConfig?: CsrConfig } };
37
- })
38
- );
39
- const getPageState = (csrConfig?: CsrConfig) => {
40
- const { transition, safeArea, topInset, bottomInset, gesture, cache }: CsrConfig = csrConfig ?? {};
41
- const pageState: PageState = {
42
- transition: transition ?? "none",
43
- topSafeArea: safeArea === false ? 0 : device.topSafeArea,
44
- bottomSafeArea: safeArea === false ? 0 : device.bottomSafeArea,
45
- // topSafeArea: safeArea === false || device.info.platform === "android" ? 0 : device.topSafeArea,
46
- // bottomSafeArea: safeArea === false || device.info.platform === "android" ? 0 : device.bottomSafeArea,
47
- topInset: topInset === true ? DEFAULT_TOP_INSET : topInset === false ? 0 : (topInset ?? 0),
48
- bottomInset: bottomInset === true ? DEFAULT_BOTTOM_INSET : bottomInset === false ? 0 : (bottomInset ?? 0),
49
- gesture: gesture ?? true,
50
- cache: cache ?? false,
51
- };
52
- return pageState;
53
- };
54
-
55
- const routeMap = new Map<string, Route>();
56
- routeMap.set("/", { path: "/", children: new Map() });
57
- for (const filePath of Object.keys(pages)) {
58
- const fileName = /\.\/(.*)\.tsx$/.exec(filePath)?.[1];
59
-
60
- if (!fileName) continue;
61
- const fileType: "page" | "layout" | null = fileName.endsWith("page")
62
- ? "page"
63
- : fileName.endsWith("layout")
64
- ? "layout"
65
- : null;
66
- if (!fileType) continue;
67
- const pathSegments = [
68
- "/",
69
- ...fileName
70
- .split("/")
71
- .slice(0, -1)
72
- .map((segment) => `/${segment.replace(/\[(.*?)\]/g, ":$1")}`),
73
- ];
74
-
75
- const targetRouteMap = pathSegments.slice(0, -1).reduce((rMap: Map<string, Route>, path: string) => {
76
- if (!rMap.has(path)) rMap.set(path, { path, children: new Map() });
77
- return rMap.get(path)?.children;
78
- }, routeMap);
79
- if (!targetRouteMap) continue;
80
- const targetPath = pathSegments[pathSegments.length - 1];
81
-
82
- targetRouteMap.set(targetPath, {
83
- // action: pages[path]?.action,
84
- // ErrorBoundary: pages[path]?.ErrorBoundary,
85
- ...(targetRouteMap.get(targetPath) ?? { path: targetPath, children: new Map<string, Route>() }),
86
- ...(fileType === "layout"
87
- ? { Layout: pages[filePath].default }
88
- : {
89
- Page: pages[filePath].default,
90
- pageState: getPageState(pages[filePath].default.csrConfig),
91
- csrConfig: pages[filePath].default.csrConfig,
92
- }),
93
- } as Route);
94
- }
95
- const pathname = window.location.pathname;
96
- const initialPath = device.lang + entryPath;
97
- window.document.body.style.overflow = "hidden";
98
-
99
- const getPathRoutes = (
100
- route: Route,
101
- parentRootLayouts: (
102
- | (({ children, params, searchParams }) => ReactNode)
103
- | (({ children, params, searchParams }) => Promise<ReactNode>)
104
- )[] = [],
105
- parentLayouts: (
106
- | (({ children, params, searchParams }) => ReactNode)
107
- | (({ children, params, searchParams }) => Promise<ReactNode>)
108
- )[] = [],
109
- parentPaths: string[] = []
110
- ): PathRoute[] => {
111
- const parentPath = parentPaths.filter((path) => path !== "/").join("");
112
- const currentPathSegment = /^\/\(.*\)$/.test(route.path) ? "" : route.path;
113
- const isRoot = ["/", "/:lang"].includes(parentPath + currentPathSegment) && parentRootLayouts.length < 2;
114
- const path = parentPath + currentPathSegment;
115
- const pathSegments = [...parentPaths, ...(currentPathSegment ? [currentPathSegment] : [])];
116
- const RootLayouts = [...parentRootLayouts, ...(isRoot && route.Layout ? [route.Layout] : [])];
117
- const Layouts = [...parentLayouts, ...(!isRoot && route.Layout ? [route.Layout] : [])];
118
- return [
119
- ...(route.Page
120
- ? [
121
- {
122
- path,
123
- pathSegments,
124
- Page: route.Page,
125
- RootLayouts,
126
- Layouts,
127
- pageState: route.pageState ?? defaultPageState,
128
- },
129
- ]
130
- : []),
131
- ...(route.children.size
132
- ? [...route.children.values()].flatMap((child) => getPathRoutes(child, RootLayouts, Layouts, pathSegments))
133
- : []),
134
- ];
135
- };
136
- const rootRoute = routeMap.get("/");
137
- if (!rootRoute) throw new Error("No root route");
138
- const pathRoutes = getPathRoutes(rootRoute);
139
- const routeGuide: RouteGuide = { pathSegment: "/", children: {} };
140
- pathRoutes.forEach((pathRoute) => {
141
- const pathSegments = pathRoute.pathSegments.slice(1);
142
- pathSegments.reduce((routeGuide, pathSegment, index) => {
143
- const child = routeGuide.children[pathSegment] as RouteGuide | undefined;
144
- routeGuide.children[pathSegment] = {
145
- ...(child ?? {}),
146
- pathSegment,
147
- ...(index === pathSegments.length - 1 ? { pathRoute } : {}),
148
- children: (child?.children as { [key: string]: RouteGuide } | undefined) ?? {},
149
- } as RouteGuide;
150
- return routeGuide.children[pathSegment];
151
- }, routeGuide);
152
- });
153
- const RouterProvider = () => {
154
- const csrValues = useCsrValues(routeGuide, pathRoutes);
155
- const { location } = csrValues;
156
- return (
157
- <csrContext.Provider value={csrValues}>
158
- {location.pathRoute.RootLayouts.reduceRight(
159
- (children, Layout: any) => {
160
- return (
161
- <Layout params={location.params} searchParams={location.searchParams}>
162
- {children}
163
- </Layout>
164
- );
165
- },
166
- <></>
167
- )}
168
- </csrContext.Provider>
169
- );
170
- };
171
- if (pathname !== `/${initialPath}`) {
172
- window.location.replace(initialPath);
173
- return;
174
- } else {
175
- const el = document.getElementById("root");
176
- if (!el) throw new Error("No root element");
177
- const root = ReactDOM.createRoot(el);
178
- root.render(<RouterProvider />);
179
- }
180
- };
@@ -1,45 +0,0 @@
1
- import { logo } from "@akanjs/base";
2
- import { Logger } from "@akanjs/common";
3
- import { match as matchLocale } from "@formatjs/intl-localematcher";
4
- import Negotiator from "negotiator";
5
- import { NextRequest, NextResponse } from "next/server";
6
-
7
- const i18n = { defaultLocale: "en", locales: ["en", "ko"] };
8
- const basePaths = process.env.basePaths ? process.env.basePaths.split(",") : [];
9
-
10
- function getLocale(request: NextRequest): string | undefined {
11
- if (!request.headers.get("accept-language")) return i18n.defaultLocale;
12
- const negotiatorHeaders: Record<string, string> = {};
13
- request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));
14
- try {
15
- const languages = new Negotiator({ headers: negotiatorHeaders }).languages();
16
- return matchLocale(languages, i18n.locales, i18n.defaultLocale);
17
- } catch (e) {
18
- return i18n.defaultLocale;
19
- }
20
- }
21
- export const createNextMiddleware = () => {
22
- Logger.rawLog(logo, "console");
23
- const middleware = (request: NextRequest) => {
24
- const pathname = request.nextUrl.pathname;
25
- const pathnameIsMissingLocale = i18n.locales.every(
26
- (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
27
- );
28
- if (pathnameIsMissingLocale)
29
- return NextResponse.redirect(
30
- new URL(`/${getLocale(request)}/${request.nextUrl.href.split("/").slice(3).join("/")}`, request.url)
31
- );
32
- const splits = pathname.split("/");
33
- const locale = splits[1];
34
- const basePath = basePaths.includes(splits[2]) ? splits[2] : null;
35
- const headers = new Headers(request.headers);
36
- const searchParams = new URLSearchParams(request.nextUrl.search);
37
- const searchParamJwt = searchParams.get("jwt");
38
- headers.set("x-locale", locale);
39
- headers.set("x-path", "/" + splits.slice(2).join("/"));
40
- if (basePath) headers.set("x-base-path", basePath);
41
- if (searchParamJwt) headers.set("jwt", searchParamJwt);
42
- return NextResponse.next({ request: { headers } });
43
- };
44
- return middleware;
45
- };
@@ -1,14 +0,0 @@
1
- import { MetadataRoute } from "next";
2
-
3
- export const createRobotPage = (clientHttpUri: string, config?: MetadataRoute.Robots): MetadataRoute.Robots => {
4
- return {
5
- ...(config ?? {}),
6
- rules: {
7
- userAgent: "*",
8
- allow: "/",
9
- disallow: "/admin/",
10
- ...(config?.rules ?? {}),
11
- },
12
- sitemap: `${clientHttpUri}/sitemap.xml`,
13
- };
14
- };
@@ -1,6 +0,0 @@
1
- import { MetadataRoute } from "next";
2
-
3
- const lastModified = new Date();
4
- export const createSitemapPage = (clientHttpUri: string, paths: string[]): MetadataRoute.Sitemap => {
5
- return paths.map((path) => ({ url: `${clientHttpUri}${path}`, lastModified }));
6
- };
package/index.ts DELETED
@@ -1,23 +0,0 @@
1
- export type * from "./types";
2
- export { useFetch } from "./useFetch";
3
- export { lazy } from "./lazy";
4
- export { makePageProto } from "./makePageProto";
5
- export { useDebounce } from "./useDebounce";
6
- export { useInterval } from "./useInterval";
7
- export { bootCsr } from "./bootCsr";
8
- export { useCamera } from "./useCamera";
9
- export { useContact } from "./useContact";
10
- export { usePushNoti } from "./usePushNoti";
11
- export { useGeoLocation } from "./useGeoLocation";
12
- export { useCodepush } from "./useCodepush";
13
- export { usePurchase, type PlatformType, type ProductType, type CdvProductType } from "./usePurchase";
14
- export { useCsrValues } from "./useCsrValues";
15
- export { createRobotPage } from "./createRobotPage";
16
- export { createSitemapPage } from "./createSitemapPage";
17
- export { createNextMiddleware } from "./createNextMiddleware";
18
- //! PageAgent csr에서 말썽 일으킨다
19
- // export { PageAgent } from "./PageAgent";
20
-
21
- export { useThrottle } from "./useThrottle";
22
- export { useHistory } from "./useHistory";
23
- export { useLocation } from "./useLocation";
package/lazy.ts DELETED
@@ -1,9 +0,0 @@
1
- //! next build를 위해서 lint 무시
2
- /* eslint-disable @typescript-eslint/no-unsafe-call */
3
- import dynamic, { DynamicOptions } from "next/dynamic";
4
- import { ComponentType } from "react";
5
-
6
- export const lazy = <T extends ComponentType<any>>(
7
- loader: (x?: string) => Promise<{ default: T } | T>,
8
- option?: DynamicOptions<T>
9
- ) => (dynamic as any)(loader, option ?? {}) as unknown as T;
package/makePageProto.tsx DELETED
@@ -1,117 +0,0 @@
1
- import { baseClientEnv } from "@akanjs/base";
2
- import { getHeader } from "@akanjs/client";
3
- import { Logger, pathGet } from "@akanjs/common";
4
- import { type Translation, type TransMessage } from "@akanjs/dictionary";
5
- import type { ReactNode } from "react";
6
-
7
- const getPageInfo = (): { locale: string; path: string } => {
8
- if (baseClientEnv.side !== "server") {
9
- // client side, has window object
10
- return {
11
- locale: window.location.pathname.split("/")[1] ?? "en",
12
- path: "/" + window.location.pathname.split("/").slice(2).join("/"),
13
- };
14
- }
15
- const locale = getHeader("x-locale") ?? "en";
16
- const path = getHeader("x-path") ?? "/";
17
- return { locale, path };
18
- };
19
-
20
- const langIdx: Record<string, number> = { en: 0, ko: 1, zhChs: 2, zhCht: 3 };
21
- const dictionary: { [key: string]: { [key: string]: string } } = {};
22
- const translator = (lang: string, key: string, param?: Record<string, string | number>) => {
23
- const idx = langIdx[lang];
24
- try {
25
- const msg = pathGet(key, dictionary)?.[idx] as string | undefined;
26
- if (!msg) {
27
- Logger.error(`No translation for ${key}`);
28
- return key;
29
- }
30
- return param ? msg.replace(/{([^}]+)}/g, (_, key: string) => param[key] as string) : msg;
31
- } catch (e) {
32
- return key;
33
- }
34
- };
35
- translator.rich = (lang: string, key: string, param?: Record<string, string>) => {
36
- const idx = langIdx[lang];
37
- const msg = pathGet(key, dictionary)?.[idx] as string | undefined;
38
- if (!msg) {
39
- Logger.error(`No translation for ${key}`);
40
- return key;
41
- }
42
- return param ? msg.replace(/{([^}]+)}/g, (_, key: string) => param[key]) : msg;
43
- };
44
-
45
- export const makePageProto = <Locale extends { [key: string]: { [key: string]: Translation } }>(locales: Locale[]) => {
46
- locales.forEach((locale) => {
47
- Object.keys(locale).forEach((key: string) => (dictionary[key] = Object.assign(dictionary[key] ?? {}, locale[key])));
48
- });
49
- return () => {
50
- const { locale, path } = getPageInfo();
51
- const lang = locale;
52
- const l = (key: TransMessage<Locale>, param?: { [key: string]: string | number }) => translator(lang, key, param);
53
- l.rich = (key: TransMessage<Locale>, param?: { [key: string]: string | number }) =>
54
- (
55
- <span
56
- dangerouslySetInnerHTML={{
57
- __html: translator.rich(lang, key, {
58
- ...param,
59
- // strong: (chunks: string) => `<b>${chunks}</b>`,
60
- // "bg-primary": (chunks: string) => `<span className="bg-primary text-base-100">${chunks}</span>`,
61
- // primary: (chunks: string) => `<span className="bg-base-100 text-primary">${chunks}</span>`,
62
- br: `<br />`,
63
- }),
64
- }}
65
- />
66
- ) as ReactNode;
67
- l.field = <ModelKey extends keyof Locale>(model: ModelKey, field: keyof Locale[ModelKey]) => {
68
- const key = `${model as string}.${field as string}` as unknown as TransMessage<Locale>;
69
- return l(key);
70
- };
71
- l.desc = <ModelKey extends keyof Locale>(model: ModelKey, field: keyof Locale[ModelKey]) => {
72
- const key = `${model as string}.desc-${field as string}` as unknown as TransMessage<Locale>;
73
- return l(key);
74
- };
75
- l.enum = <ModelKey extends keyof Locale>(model: ModelKey, field: keyof Locale[ModelKey], value: string) => {
76
- const key = `${model as string}.enum-${field as string}-${value}` as unknown as TransMessage<Locale>;
77
- return l(key);
78
- };
79
- l.enumdesc = <ModelKey extends keyof Locale>(model: ModelKey, field: keyof Locale[ModelKey], value: string) => {
80
- const key = `${model as string}.enumdesc-${field as string}-${value}` as unknown as TransMessage<Locale>;
81
- return l(key);
82
- };
83
- l.api = <ModelKey extends keyof Locale>(model: ModelKey, endpoint: keyof Locale[ModelKey]) => {
84
- const key = `${model as string}.api-${endpoint as string}` as unknown as TransMessage<Locale>;
85
- return l(key);
86
- };
87
- l.apidesc = <ModelKey extends keyof Locale>(model: ModelKey, endpoint: keyof Locale[ModelKey]) => {
88
- const key = `${model as string}.apidesc-${endpoint as string}` as unknown as TransMessage<Locale>;
89
- return l(key);
90
- };
91
- l.arg = <ModelKey extends keyof Locale>(model: ModelKey, endpoint: keyof Locale[ModelKey], arg: string) => {
92
- const key = `${model as string}.arg-${endpoint as string}-${arg}` as unknown as TransMessage<Locale>;
93
- return l(key);
94
- };
95
- l.argdesc = <ModelKey extends keyof Locale>(model: ModelKey, endpoint: keyof Locale[ModelKey], arg: string) => {
96
- const key = `${model as string}.argdesc-${endpoint as string}-${arg}` as unknown as TransMessage<Locale>;
97
- return l(key);
98
- };
99
- l.qry = <ModelKey extends keyof Locale>(model: ModelKey, queryKey: keyof Locale[ModelKey]) => {
100
- const key = `${model as string}.qry-${queryKey as string}` as unknown as TransMessage<Locale>;
101
- return l(key);
102
- };
103
- l.qrydesc = <ModelKey extends keyof Locale>(model: ModelKey, queryKey: keyof Locale[ModelKey]) => {
104
- const key = `${model as string}.qrydesc-${queryKey as string}` as unknown as TransMessage<Locale>;
105
- return l(key);
106
- };
107
- l.qarg = <ModelKey extends keyof Locale>(model: ModelKey, queryKey: keyof Locale[ModelKey], arg: string) => {
108
- const key = `${model as string}.qarg-${queryKey as string}-${arg}` as unknown as TransMessage<Locale>;
109
- return l(key);
110
- };
111
- l.qargdesc = <ModelKey extends keyof Locale>(model: ModelKey, queryKey: keyof Locale[ModelKey], arg: string) => {
112
- const key = `${model as string}.qargdesc-${queryKey as string}-${arg}` as unknown as TransMessage<Locale>;
113
- return l(key);
114
- };
115
- return { path, l, lang };
116
- };
117
- };
package/types.ts DELETED
@@ -1,7 +0,0 @@
1
- export type LoginAuth = "user" | "admin" | "public";
2
- export interface LoginForm {
3
- auth: LoginAuth;
4
- redirect?: string;
5
- unauthorize?: string;
6
- jwt?: string | null;
7
- }
package/useCamera.tsx DELETED
@@ -1,94 +0,0 @@
1
- "use client";
2
- import { device } from "@akanjs/client";
3
- import { Camera, CameraResultType, CameraSource, PermissionStatus } from "@capacitor/camera";
4
- import { useEffect, useState } from "react";
5
-
6
- export const useCamera = () => {
7
- const [permissions, setPermissions] = useState<PermissionStatus>({ camera: "prompt", photos: "prompt" });
8
-
9
- /**
10
- * 최초로 킬 경우 권한은 prompt 상태이다.
11
- * prompt 상태일 경우 권한을 요청한다.
12
- * 권한이 denied 상태일 경우 설정으로 이동한다.
13
- * 이후 state의 permission을 업데이트해야한다.
14
- *
15
- */
16
- const checkPermission = async (type: "photos" | "camera" | "all") => {
17
- try {
18
- if (type === "photos") {
19
- if (permissions.photos === "prompt") {
20
- const { photos } = await Camera.requestPermissions();
21
- setPermissions((prev) => ({ ...prev, photos }));
22
- } else if (permissions.photos === "denied") {
23
- location.assign("app-settings:");
24
- return;
25
- }
26
- } else if (type === "camera") {
27
- if (permissions.camera === "prompt") {
28
- const { camera } = await Camera.requestPermissions();
29
- setPermissions((prev) => ({ ...prev, camera }));
30
- } else if (permissions.camera === "denied") {
31
- location.assign("app-settings:");
32
- return;
33
- }
34
- } else {
35
- if (permissions.camera === "prompt" || permissions.photos === "prompt") {
36
- const permissions = await Camera.requestPermissions();
37
- setPermissions(permissions);
38
- } else if (permissions.camera === "denied" || permissions.photos === "denied") {
39
- location.assign("app-settings:");
40
- return;
41
- }
42
- }
43
- } catch (e) {
44
- //
45
- }
46
- };
47
-
48
- const getPhoto = async (src: "prompt" | "camera" | "photos" = "prompt") => {
49
- const source =
50
- device.info.platform !== "web"
51
- ? src === "prompt"
52
- ? CameraSource.Prompt
53
- : src === "camera"
54
- ? CameraSource.Camera
55
- : CameraSource.Photos
56
- : CameraSource.Photos;
57
- const permission = src === "prompt" ? "all" : src === "camera" ? "camera" : "photos";
58
- void checkPermission(permission);
59
- try {
60
- const photo = await Camera.getPhoto({
61
- quality: 100,
62
- source,
63
- allowEditing: false,
64
- resultType: CameraResultType.DataUrl,
65
- promptLabelHeader: "프로필 사진을 올려주세요",
66
- promptLabelPhoto: "앨범에서 선택하기",
67
- promptLabelPicture: "사진 찍기",
68
- promptLabelCancel: "취소",
69
- });
70
- return photo;
71
- } catch (e) {
72
- if (e === "User cancelled photos app") return;
73
- }
74
- };
75
-
76
- const pickImage = async () => {
77
- void checkPermission("photos");
78
- const photo = await Camera.pickImages({
79
- quality: 90,
80
- });
81
-
82
- return photo;
83
- };
84
-
85
- useEffect(() => {
86
- void (async () => {
87
- if (device.info.platform !== "web") {
88
- const permissions = await Camera.checkPermissions();
89
- setPermissions(permissions);
90
- }
91
- })();
92
- }, []);
93
- return { permissions, getPhoto, pickImage, checkPermission };
94
- };
package/useCodepush.tsx DELETED
@@ -1,98 +0,0 @@
1
- "use client";
2
- import { mergeVersion, splitVersion } from "@akanjs/common";
3
- import type { ProtoAppInfo, ProtoFile } from "@akanjs/constant";
4
- import { App } from "@capacitor/app";
5
- import { Device } from "@capacitor/device";
6
- import { CapacitorUpdater } from "@capgo/capacitor-updater";
7
- import axios from "axios";
8
- import { useState } from "react";
9
-
10
- export const useCodepush = ({ serverUrl, branch }: { serverUrl: string; branch: "debug" | "develop" | "main" }) => {
11
- const [update, setUpdate] = useState(false);
12
- const [version, setVersion] = useState("");
13
-
14
- const initialize = async () => {
15
- await CapacitorUpdater.notifyAppReady();
16
- };
17
- const checkNewRelease = async () => {
18
- //*appInfo 정의
19
- const info = await Device.getInfo();
20
- const app = await App.getInfo();
21
- const pluginVersion = await CapacitorUpdater.getPluginVersion();
22
- const { deviceId } = await CapacitorUpdater.getDeviceId();
23
- const { bundle: version, native } = await CapacitorUpdater.current();
24
- const builtInversion = await CapacitorUpdater.getBuiltinVersion();
25
- const appId = app.id;
26
- const platform = info.platform;
27
-
28
- window.alert(
29
- `getBuildinVersion:${builtInversion.version}\ncurrent.bundle:${version.version}\ncurrennt.native:${native}`
30
- );
31
- /**
32
- * "version_name": "builtin",
33
- * "version_code": "1",
34
- * "app_id": "com.lu.app",
35
- * "plugin_version": "5.6.9",
36
- * "version_build": "1.0",
37
- * "is_prod": true,
38
- * "version_os": "17.0.1",
39
- * "is_emulator": true,
40
- * "custom_id": "",
41
- * "device_id": "C77000B1-7D28-4697-ADE0-74452F47C350",
42
- * "platform": "ios",
43
- * "defaultChannel": ""
44
- */
45
- const { major, minor, patch } = splitVersion(version.version === "builtin" ? app.version : version.version);
46
- const appName = process.env.NEXT_PUBLIC_APP_NAME ?? "";
47
-
48
- const appInfo: ProtoAppInfo = {
49
- appId,
50
- appName,
51
- deviceId: deviceId,
52
- platform: platform as "ios" | "android",
53
- branch,
54
- isEmulator: info.isVirtual,
55
- major: parseInt(major),
56
- minor: parseInt(minor),
57
- patch: parseInt(patch),
58
- buildNum: app.build, //앱내 빌드시 버전 횟수 모르면 고한테 물어보기
59
- versionOs: info.osVersion,
60
- };
61
- //fix lu to akasys
62
- const url = serverUrl.replace("lu", "akasys");
63
- const release = (
64
- await axios.post<(ProtoAppInfo & { appBuild: string }) | null>(`${url}/release/codepush`, {
65
- data: { ...appInfo },
66
- })
67
- ).data;
68
- if (!release) return;
69
- const file = (await axios.get<ProtoFile>(`${url}/file/file/${release.appBuild}`)).data;
70
-
71
- return { release: release, bundleFile: file };
72
- //* fetch로 서버에게 내 AppInfo 전달.
73
- // return await fetch.requestRelease();
74
- };
75
-
76
- const codepush = async () => {
77
- //* isNeedUpdate로 업데이트 필요한지 확인
78
- const isNewRelease = await checkNewRelease();
79
- if (!isNewRelease) return;
80
- const { release, bundleFile } = isNewRelease;
81
- setUpdate(true);
82
- const bundle = await CapacitorUpdater.download({
83
- url: bundleFile.url,
84
- version: mergeVersion(release.major, release.minor, release.patch),
85
- });
86
- //* 해제한 파일로 업데이트
87
- await CapacitorUpdater.set(bundle);
88
- };
89
- const getVersion = async () => {
90
- return await CapacitorUpdater.getBuiltinVersion();
91
- };
92
-
93
- const statManager = async () => {
94
- // 업데이트 통계 서버에 전달
95
- };
96
-
97
- return { update, version, initialize, checkNewRelease, codepush, statManager };
98
- };