@kendevelops/auth-flow-kit 1.1.0 → 1.1.2
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/dist/index.cjs +40 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -98,56 +98,68 @@ async function httpJSON(url, opts = {}, withAuth = false) {
|
|
|
98
98
|
|
|
99
99
|
// src/AuthContext.tsx
|
|
100
100
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
101
|
-
var
|
|
102
|
-
var AuthContext = (0, import_react.createContext)(
|
|
101
|
+
var USER_STORAGE_KEY = "afk_user";
|
|
102
|
+
var AuthContext = (0, import_react.createContext)(null);
|
|
103
103
|
function useAuth() {
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
104
|
+
const ctx = (0, import_react.useContext)(AuthContext);
|
|
105
|
+
if (!ctx) {
|
|
106
106
|
throw new Error("useAuth must be used inside AuthProvider");
|
|
107
107
|
}
|
|
108
|
-
return
|
|
108
|
+
return ctx;
|
|
109
109
|
}
|
|
110
|
-
function
|
|
111
|
-
const
|
|
112
|
-
return
|
|
110
|
+
function initState() {
|
|
111
|
+
const stored = localStorage.getItem(USER_STORAGE_KEY);
|
|
112
|
+
return {
|
|
113
|
+
user: stored ? JSON.parse(stored) : null,
|
|
114
|
+
loading: false
|
|
115
|
+
};
|
|
113
116
|
}
|
|
114
117
|
function AuthProvider({
|
|
115
118
|
config,
|
|
116
119
|
children
|
|
117
120
|
}) {
|
|
118
|
-
const [user,
|
|
119
|
-
const [loading, setLoading] = (0, import_react.useState)(true);
|
|
121
|
+
const [{ user, loading }, setState] = (0, import_react.useState)(initState);
|
|
120
122
|
const { baseURL, endpoints, onLoginSuccess, onLogout } = config;
|
|
121
123
|
const getToken = () => getStoredAccessToken();
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
const applyAuthResponse = (res) => {
|
|
125
|
+
setStoredAccessToken(res.accessToken);
|
|
126
|
+
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(res.user));
|
|
127
|
+
setState({
|
|
128
|
+
user: res.user,
|
|
129
|
+
loading: false
|
|
130
|
+
});
|
|
131
|
+
onLoginSuccess?.();
|
|
132
|
+
};
|
|
133
|
+
const login = async (email, password) => {
|
|
126
134
|
const response = await httpJSON(
|
|
127
|
-
makeURL(baseURL,
|
|
135
|
+
makeURL(baseURL, endpoints.login),
|
|
128
136
|
{
|
|
129
137
|
method: "POST",
|
|
130
|
-
body: JSON.stringify(
|
|
138
|
+
body: JSON.stringify({ email, password })
|
|
131
139
|
}
|
|
132
140
|
);
|
|
133
|
-
|
|
134
|
-
localStorage.setItem(USER_KEY, JSON.stringify(response.user));
|
|
135
|
-
setUser(response.user);
|
|
136
|
-
onLoginSuccess?.();
|
|
137
|
-
};
|
|
138
|
-
const login = async (email, password) => {
|
|
139
|
-
await runAuthRequest(endpoints.login, { email, password });
|
|
141
|
+
applyAuthResponse(response);
|
|
140
142
|
};
|
|
141
143
|
const signup = async (payload) => {
|
|
142
|
-
await
|
|
144
|
+
const response = await httpJSON(
|
|
145
|
+
makeURL(baseURL, endpoints.signup),
|
|
146
|
+
{
|
|
147
|
+
method: "POST",
|
|
148
|
+
body: JSON.stringify(payload)
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
applyAuthResponse(response);
|
|
143
152
|
};
|
|
144
153
|
const logout = () => {
|
|
145
154
|
setStoredAccessToken(null);
|
|
146
|
-
localStorage.removeItem(
|
|
147
|
-
|
|
155
|
+
localStorage.removeItem(USER_STORAGE_KEY);
|
|
156
|
+
setState({
|
|
157
|
+
user: null,
|
|
158
|
+
loading: false
|
|
159
|
+
});
|
|
148
160
|
onLogout?.();
|
|
149
161
|
};
|
|
150
|
-
const
|
|
162
|
+
const value = (0, import_react.useMemo)(
|
|
151
163
|
() => ({
|
|
152
164
|
user,
|
|
153
165
|
loading,
|
|
@@ -159,7 +171,7 @@ function AuthProvider({
|
|
|
159
171
|
}),
|
|
160
172
|
[user, loading, config]
|
|
161
173
|
);
|
|
162
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value
|
|
174
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value, children });
|
|
163
175
|
}
|
|
164
176
|
|
|
165
177
|
// src/Protected.tsx
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/http.ts","../src/Protected.tsx","../src/screens/LoginScreen.tsx","../src/screens/PasswordResetScreen.tsx","../src/screens/SignupScreen.tsx"],"sourcesContent":["export { AuthProvider, useAuth } from \"./AuthContext\";\r\nexport { default as Protected } from \"./Protected\";\r\n\r\n// Screens\r\nexport { default as LoginScreen } from \"./screens/LoginScreen\";\r\nexport { default as SignupScreen } from \"./screens/SignupScreen\";\r\nexport { default as PasswordResetScreen } from \"./screens/PasswordResetScreen\";\r\n\r\n// Types\r\nexport * from \"./types\";\r\n","import React, {\r\n createContext,\r\n useContext,\r\n useMemo,\r\n useState,\r\n useEffect,\r\n PropsWithChildren,\r\n} from \"react\";\r\n\r\nimport {\r\n AuthContextType,\r\n AuthProviderConfig,\r\n StandardAuthResponse,\r\n User,\r\n} from \"./types\";\r\n\r\nimport {\r\n httpJSON,\r\n makeURL,\r\n setStoredAccessToken,\r\n getStoredAccessToken,\r\n} from \"./http\";\r\n\r\nconst USER_KEY = \"afk_user\";\r\n\r\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\r\n\r\nexport function useAuth(): AuthContextType {\r\n const value = useContext(AuthContext);\r\n if (value === undefined) {\r\n throw new Error(\"useAuth must be used inside AuthProvider\");\r\n }\r\n return value;\r\n}\r\n\r\nfunction loadUser(): User | null {\r\n const raw = localStorage.getItem(USER_KEY);\r\n return raw ? JSON.parse(raw) : null;\r\n}\r\n\r\nexport function AuthProvider({\r\n config,\r\n children,\r\n}: PropsWithChildren<{ config: AuthProviderConfig }>) {\r\n const [user, setUser] = useState<User | null>(() => loadUser());\r\n const [loading, setLoading] = useState<boolean>(true);\r\n\r\n const { baseURL, endpoints, onLoginSuccess, onLogout } = config;\r\n\r\n const getToken = () => getStoredAccessToken();\r\n\r\n useEffect(() => {\r\n setLoading(false);\r\n }, []);\r\n\r\n const runAuthRequest = async (\r\n endpoint: string,\r\n body: unknown\r\n ): Promise<void> => {\r\n const response = await httpJSON<StandardAuthResponse>(\r\n makeURL(baseURL, endpoint),\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify(body),\r\n }\r\n );\r\n\r\n setStoredAccessToken(response.accessToken);\r\n localStorage.setItem(USER_KEY, JSON.stringify(response.user));\r\n setUser(response.user);\r\n\r\n onLoginSuccess?.();\r\n };\r\n\r\n const login: AuthContextType[\"login\"] = async (email, password) => {\r\n await runAuthRequest(endpoints.login, { email, password });\r\n };\r\n\r\n const signup: AuthContextType[\"signup\"] = async (payload) => {\r\n await runAuthRequest(endpoints.signup, payload);\r\n };\r\n\r\n const logout = () => {\r\n setStoredAccessToken(null);\r\n localStorage.removeItem(USER_KEY);\r\n setUser(null);\r\n onLogout?.();\r\n };\r\n\r\n const contextValue = useMemo<AuthContextType>(\r\n () => ({\r\n user,\r\n loading,\r\n login,\r\n signup,\r\n logout,\r\n getToken,\r\n config,\r\n }),\r\n [user, loading, config]\r\n );\r\n\r\n return (\r\n <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>\r\n );\r\n}\r\n","/*\r\n This file contains the low-level HTTP utilities used internally by\r\n auth-flow-kit to communicate with the backend.\r\n\r\n It provides:\r\n - makeURL: safely joins baseURL + endpoint path\r\n - getStoredAccessToken: reads the JWT from localStorage\r\n - setStoredAccessToken: stores/removes the JWT\r\n - httpJSON: wrapper around fetch with JSON + optional auth header\r\n\r\n NOTES FOR DEVELOPERS USING THE LIBRARY:\r\n You do NOT need to import or modify anything in this file.\r\n It is an internal helper used by the AuthProvider and auth screens.\r\n\r\n This keeps the library lightweight, predictable,\r\n and familiar to developers used to Redux Toolkit-style authentication.\r\n*/\r\n\r\nexport function makeURL(baseURL: string, path: string) {\r\n return `${baseURL.replace(/\\/$/, \"\")}${\r\n path.startsWith(\"/\") ? path : `/${path}`\r\n }`;\r\n}\r\n\r\nexport function getStoredAccessToken(): string | null {\r\n try {\r\n return localStorage.getItem(\"afk_access_token\");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function setStoredAccessToken(token: string | null) {\r\n try {\r\n if (token) localStorage.setItem(\"afk_access_token\", token);\r\n else localStorage.removeItem(\"afk_access_token\");\r\n } catch {\r\n // Gonna ignore storage errors (Safari private mode, etc.) for now, not exactly needed.\r\n }\r\n}\r\n\r\nexport async function httpJSON<T>(\r\n url: string,\r\n opts: RequestInit = {},\r\n withAuth = false\r\n): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n\r\n if (withAuth) {\r\n const tok = getStoredAccessToken();\r\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\r\n }\r\n\r\n const res = await fetch(url, {\r\n ...opts,\r\n headers: { ...headers, ...(opts.headers || {}) },\r\n });\r\n\r\n if (!res.ok) {\r\n let message = `Request failed (${res.status})`;\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n\r\n // Backend returned JSON error\r\n if (contentType.includes(\"application/json\")) {\r\n try {\r\n const data = await res.json();\r\n if (data?.message) message = data.message;\r\n } catch {\r\n // ignore JSON parse errors, cos not important to me now\r\n }\r\n }\r\n\r\n // Backend returned HTML (Express default error pages)\r\n if (contentType.includes(\"text/html\")) {\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n message =\r\n \"The forgot password endpoint you added in config.endpoints.forgot does not exist in your server. Please check and update your config.endpoints.forgot\";\r\n } else {\r\n message = \"Unexpected server error\";\r\n }\r\n }\r\n\r\n // Developer-only guidance\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n console.error(\r\n `[auth-flow-kit] Password reset endpoint not found.\r\n\r\n Expected a POST route matching:\r\n ${url}\r\n\r\n Fix this by either:\r\n - Adding the route on your backend, or\r\n - Updating config.endpoints.forgot`\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n}\r\n","\"use client\";\r\n\r\n/*\r\nProtected component\r\n\r\nWraps authenticated content and prevents rendering when unauthenticated.\r\n\r\nIMPORTANT:\r\nThis component does NOT hard-redirect by default.\r\nNavigation should be handled by the host application (router or state).\r\n\r\nIf redirectTo is provided AND the host app supports routing,\r\na redirect will occur.\r\n*/\r\n\r\nimport React, { useEffect } from \"react\";\r\nimport { useAuth } from \"./AuthContext\";\r\n\r\ntype ProtectedProps = {\r\n children: React.ReactNode;\r\n redirectTo?: string;\r\n};\r\n\r\nexport default function Protected({ children, redirectTo }: ProtectedProps) {\r\n const { user, loading } = useAuth();\r\n\r\n useEffect(() => {\r\n if (!loading && !user && redirectTo) {\r\n window.location.href = redirectTo;\r\n }\r\n }, [loading, user, redirectTo]);\r\n\r\n if (loading) return <div>Loading...</div>;\r\n if (!user) return null;\r\n\r\n return <>{children}</>;\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport PasswordResetScreen from \"./PasswordResetScreen\";\r\n\r\nexport default function LoginScreen() {\r\n const { login } = useAuth();\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [showReset, setShowReset] = useState(false);\r\n\r\n if (showReset) {\r\n return (\r\n <div style={{ animation: \"fade .2s\" }}>\r\n <PasswordResetScreen />\r\n <p\r\n onClick={() => setShowReset(false)}\r\n style={{\r\n marginTop: 16,\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n textDecoration: \"underline\",\r\n }}\r\n >\r\n Back to login\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Submit\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await login(trimmedEmail, trimmedPassword);\r\n } catch (err: any) {\r\n setError(err?.message || \"Login failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Welcome Back 👋\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 10 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <p\r\n onClick={() => setShowReset(true)}\r\n style={{\r\n textAlign: \"right\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n >\r\n Forgot password?\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Signing in...\" : \"Sign in\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport { httpJSON, makeURL } from \"../http\";\r\n\r\nexport default function PasswordResetScreen() {\r\n const { config } = useAuth();\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [sent, setSent] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const requestReset = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n try {\r\n const url = makeURL(config.baseURL, config.endpoints.forgot);\r\n\r\n await httpJSON(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email }),\r\n });\r\n\r\n setSent(true);\r\n } catch (err: any) {\r\n setError(err?.message || \"Failed to request reset\");\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={requestReset}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.25s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Reset Password 🔑\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: sent ? \"-18px\" : \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"90%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: sent\r\n ? \"linear-gradient(90deg, #7aff9d, #34c759)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.3s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {sent ? \"Link Sent ✔\" : \"Send reset link\"}\r\n </button>\r\n\r\n {sent && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"#2ecc71\",\r\n textAlign: \"center\",\r\n fontSize: 15,\r\n fontWeight: 600,\r\n }}\r\n >\r\n Check your email for reset instructions.\r\n </p>\r\n )}\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\n\r\nexport default function SignupScreen() {\r\n const { signup } = useAuth();\r\n const [name, setName] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n const trimmedName = name.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword || !trimmedName) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await signup({ name, email, password });\r\n } catch (err: any) {\r\n setError(err?.message || \"Signup failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Create Account ✨\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Name\r\n </label>\r\n\r\n <input\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n placeholder=\"Your name\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Creating...\" : \"Create account\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/http.ts","../src/Protected.tsx","../src/screens/LoginScreen.tsx","../src/screens/PasswordResetScreen.tsx","../src/screens/SignupScreen.tsx"],"sourcesContent":["export { AuthProvider, useAuth } from \"./AuthContext\";\r\nexport { default as Protected } from \"./Protected\";\r\n\r\n// Screens\r\nexport { default as LoginScreen } from \"./screens/LoginScreen\";\r\nexport { default as SignupScreen } from \"./screens/SignupScreen\";\r\nexport { default as PasswordResetScreen } from \"./screens/PasswordResetScreen\";\r\n\r\n// Types\r\nexport * from \"./types\";\r\n","import React, {\r\n createContext,\r\n useContext,\r\n useMemo,\r\n useState,\r\n PropsWithChildren,\r\n} from \"react\";\r\n\r\nimport {\r\n AuthContextType,\r\n AuthProviderConfig,\r\n StandardAuthResponse,\r\n User,\r\n} from \"./types\";\r\n\r\nimport {\r\n httpJSON,\r\n makeURL,\r\n setStoredAccessToken,\r\n getStoredAccessToken,\r\n} from \"./http\";\r\n\r\nconst USER_STORAGE_KEY = \"afk_user\";\r\n\r\ntype AuthState = {\r\n user: User | null;\r\n loading: boolean;\r\n};\r\n\r\nconst AuthContext = createContext<AuthContextType | null>(null);\r\n\r\nexport function useAuth(): AuthContextType {\r\n const ctx = useContext(AuthContext);\r\n if (!ctx) {\r\n throw new Error(\"useAuth must be used inside AuthProvider\");\r\n }\r\n return ctx;\r\n}\r\n\r\nfunction initState(): AuthState {\r\n const stored = localStorage.getItem(USER_STORAGE_KEY);\r\n return {\r\n user: stored ? JSON.parse(stored) : null,\r\n loading: false,\r\n };\r\n}\r\n\r\nexport function AuthProvider({\r\n config,\r\n children,\r\n}: PropsWithChildren<{ config: AuthProviderConfig }>) {\r\n const [{ user, loading }, setState] = useState<AuthState>(initState);\r\n\r\n const { baseURL, endpoints, onLoginSuccess, onLogout } = config;\r\n\r\n const getToken = () => getStoredAccessToken();\r\n\r\n const applyAuthResponse = (res: StandardAuthResponse) => {\r\n setStoredAccessToken(res.accessToken);\r\n localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(res.user));\r\n\r\n setState({\r\n user: res.user,\r\n loading: false,\r\n });\r\n\r\n onLoginSuccess?.();\r\n };\r\n\r\n const login: AuthContextType[\"login\"] = async (email, password) => {\r\n const response = await httpJSON<StandardAuthResponse>(\r\n makeURL(baseURL, endpoints.login),\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify({ email, password }),\r\n }\r\n );\r\n\r\n applyAuthResponse(response);\r\n };\r\n\r\n const signup: AuthContextType[\"signup\"] = async (payload) => {\r\n const response = await httpJSON<StandardAuthResponse>(\r\n makeURL(baseURL, endpoints.signup),\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify(payload),\r\n }\r\n );\r\n\r\n applyAuthResponse(response);\r\n };\r\n\r\n const logout = () => {\r\n setStoredAccessToken(null);\r\n localStorage.removeItem(USER_STORAGE_KEY);\r\n\r\n setState({\r\n user: null,\r\n loading: false,\r\n });\r\n\r\n onLogout?.();\r\n };\r\n\r\n const value = useMemo<AuthContextType>(\r\n () => ({\r\n user,\r\n loading,\r\n login,\r\n signup,\r\n logout,\r\n getToken,\r\n config,\r\n }),\r\n [user, loading, config]\r\n );\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n","/*\r\n This file contains the low-level HTTP utilities used internally by\r\n auth-flow-kit to communicate with the backend.\r\n\r\n It provides:\r\n - makeURL: safely joins baseURL + endpoint path\r\n - getStoredAccessToken: reads the JWT from localStorage\r\n - setStoredAccessToken: stores/removes the JWT\r\n - httpJSON: wrapper around fetch with JSON + optional auth header\r\n\r\n NOTES FOR DEVELOPERS USING THE LIBRARY:\r\n You do NOT need to import or modify anything in this file.\r\n It is an internal helper used by the AuthProvider and auth screens.\r\n\r\n This keeps the library lightweight, predictable,\r\n and familiar to developers used to Redux Toolkit-style authentication.\r\n*/\r\n\r\nexport function makeURL(baseURL: string, path: string) {\r\n return `${baseURL.replace(/\\/$/, \"\")}${\r\n path.startsWith(\"/\") ? path : `/${path}`\r\n }`;\r\n}\r\n\r\nexport function getStoredAccessToken(): string | null {\r\n try {\r\n return localStorage.getItem(\"afk_access_token\");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function setStoredAccessToken(token: string | null) {\r\n try {\r\n if (token) localStorage.setItem(\"afk_access_token\", token);\r\n else localStorage.removeItem(\"afk_access_token\");\r\n } catch {\r\n // Gonna ignore storage errors (Safari private mode, etc.) for now, not exactly needed.\r\n }\r\n}\r\n\r\nexport async function httpJSON<T>(\r\n url: string,\r\n opts: RequestInit = {},\r\n withAuth = false\r\n): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n\r\n if (withAuth) {\r\n const tok = getStoredAccessToken();\r\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\r\n }\r\n\r\n const res = await fetch(url, {\r\n ...opts,\r\n headers: { ...headers, ...(opts.headers || {}) },\r\n });\r\n\r\n if (!res.ok) {\r\n let message = `Request failed (${res.status})`;\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n\r\n // Backend returned JSON error\r\n if (contentType.includes(\"application/json\")) {\r\n try {\r\n const data = await res.json();\r\n if (data?.message) message = data.message;\r\n } catch {\r\n // ignore JSON parse errors, cos not important to me now\r\n }\r\n }\r\n\r\n // Backend returned HTML (Express default error pages)\r\n if (contentType.includes(\"text/html\")) {\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n message =\r\n \"The forgot password endpoint you added in config.endpoints.forgot does not exist in your server. Please check and update your config.endpoints.forgot\";\r\n } else {\r\n message = \"Unexpected server error\";\r\n }\r\n }\r\n\r\n // Developer-only guidance\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n console.error(\r\n `[auth-flow-kit] Password reset endpoint not found.\r\n\r\n Expected a POST route matching:\r\n ${url}\r\n\r\n Fix this by either:\r\n - Adding the route on your backend, or\r\n - Updating config.endpoints.forgot`\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n}\r\n","\"use client\";\r\n\r\n/*\r\nProtected component\r\n\r\nWraps authenticated content and prevents rendering when unauthenticated.\r\n\r\nIMPORTANT:\r\nThis component does NOT hard-redirect by default.\r\nNavigation should be handled by the host application (router or state).\r\n\r\nIf redirectTo is provided AND the host app supports routing,\r\na redirect will occur.\r\n*/\r\n\r\nimport React, { useEffect } from \"react\";\r\nimport { useAuth } from \"./AuthContext\";\r\n\r\ntype ProtectedProps = {\r\n children: React.ReactNode;\r\n redirectTo?: string;\r\n};\r\n\r\nexport default function Protected({ children, redirectTo }: ProtectedProps) {\r\n const { user, loading } = useAuth();\r\n\r\n useEffect(() => {\r\n if (!loading && !user && redirectTo) {\r\n window.location.href = redirectTo;\r\n }\r\n }, [loading, user, redirectTo]);\r\n\r\n if (loading) return <div>Loading...</div>;\r\n if (!user) return null;\r\n\r\n return <>{children}</>;\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport PasswordResetScreen from \"./PasswordResetScreen\";\r\n\r\nexport default function LoginScreen() {\r\n const { login } = useAuth();\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [showReset, setShowReset] = useState(false);\r\n\r\n if (showReset) {\r\n return (\r\n <div style={{ animation: \"fade .2s\" }}>\r\n <PasswordResetScreen />\r\n <p\r\n onClick={() => setShowReset(false)}\r\n style={{\r\n marginTop: 16,\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n textDecoration: \"underline\",\r\n }}\r\n >\r\n Back to login\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Submit\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await login(trimmedEmail, trimmedPassword);\r\n } catch (err: any) {\r\n setError(err?.message || \"Login failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Welcome Back 👋\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 10 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <p\r\n onClick={() => setShowReset(true)}\r\n style={{\r\n textAlign: \"right\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n >\r\n Forgot password?\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Signing in...\" : \"Sign in\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport { httpJSON, makeURL } from \"../http\";\r\n\r\nexport default function PasswordResetScreen() {\r\n const { config } = useAuth();\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [sent, setSent] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const requestReset = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n try {\r\n const url = makeURL(config.baseURL, config.endpoints.forgot);\r\n\r\n await httpJSON(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email }),\r\n });\r\n\r\n setSent(true);\r\n } catch (err: any) {\r\n setError(err?.message || \"Failed to request reset\");\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={requestReset}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.25s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Reset Password 🔑\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: sent ? \"-18px\" : \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"90%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: sent\r\n ? \"linear-gradient(90deg, #7aff9d, #34c759)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.3s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {sent ? \"Link Sent ✔\" : \"Send reset link\"}\r\n </button>\r\n\r\n {sent && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"#2ecc71\",\r\n textAlign: \"center\",\r\n fontSize: 15,\r\n fontWeight: 600,\r\n }}\r\n >\r\n Check your email for reset instructions.\r\n </p>\r\n )}\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\n\r\nexport default function SignupScreen() {\r\n const { signup } = useAuth();\r\n const [name, setName] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n const trimmedName = name.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword || !trimmedName) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await signup({ name, email, password });\r\n } catch (err: any) {\r\n setError(err?.message || \"Signup failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Create Account ✨\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Name\r\n </label>\r\n\r\n <input\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n placeholder=\"Your name\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Creating...\" : \"Create account\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAMO;;;ACYA,SAAS,QAAQ,SAAiB,MAAc;AACrD,SAAO,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,GAClC,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI,EACxC;AACF;AAEO,SAAS,uBAAsC;AACpD,MAAI;AACF,WAAO,aAAa,QAAQ,kBAAkB;AAAA,EAChD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,qBAAqB,OAAsB;AACzD,MAAI;AACF,QAAI,MAAO,cAAa,QAAQ,oBAAoB,KAAK;AAAA,QACpD,cAAa,WAAW,kBAAkB;AAAA,EACjD,QAAQ;AAAA,EAER;AACF;AAEA,eAAsB,SACpB,KACA,OAAoB,CAAC,GACrB,WAAW,OACC;AACZ,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,EAClB;AAEA,MAAI,UAAU;AACZ,UAAM,MAAM,qBAAqB;AACjC,QAAI,IAAK,SAAQ,eAAe,IAAI,UAAU,GAAG;AAAA,EACnD;AAEA,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,GAAG;AAAA,IACH,SAAS,EAAE,GAAG,SAAS,GAAI,KAAK,WAAW,CAAC,EAAG;AAAA,EACjD,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,UAAU,mBAAmB,IAAI,MAAM;AAC3C,UAAM,cAAc,IAAI,QAAQ,IAAI,cAAc,KAAK;AAGvD,QAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,UAAI;AACF,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAI,MAAM,QAAS,WAAU,KAAK;AAAA,MACpC,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,QAAI,YAAY,SAAS,WAAW,GAAG;AACrC,UAAI,IAAI,WAAW,OAAO,IAAI,SAAS,QAAQ,GAAG;AAChD,kBACE;AAAA,MACJ,OAAO;AACL,kBAAU;AAAA,MACZ;AAAA,IACF;AAGA,QAAI,IAAI,WAAW,OAAO,IAAI,SAAS,QAAQ,GAAG;AAChD,cAAQ;AAAA,QACN;AAAA;AAAA;AAAA,YAGI,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA,MAKT;AAAA,IACF;AAEA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAO,IAAI,KAAK;AAClB;;;ADgBS;AAhGT,IAAM,mBAAmB;AAOzB,IAAM,kBAAc,4BAAsC,IAAI;AAEvD,SAAS,UAA2B;AACzC,QAAM,UAAM,yBAAW,WAAW;AAClC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,SAAO;AACT;AAEA,SAAS,YAAuB;AAC9B,QAAM,SAAS,aAAa,QAAQ,gBAAgB;AACpD,SAAO;AAAA,IACL,MAAM,SAAS,KAAK,MAAM,MAAM,IAAI;AAAA,IACpC,SAAS;AAAA,EACX;AACF;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AACF,GAAsD;AACpD,QAAM,CAAC,EAAE,MAAM,QAAQ,GAAG,QAAQ,QAAI,uBAAoB,SAAS;AAEnE,QAAM,EAAE,SAAS,WAAW,gBAAgB,SAAS,IAAI;AAEzD,QAAM,WAAW,MAAM,qBAAqB;AAE5C,QAAM,oBAAoB,CAAC,QAA8B;AACvD,yBAAqB,IAAI,WAAW;AACpC,iBAAa,QAAQ,kBAAkB,KAAK,UAAU,IAAI,IAAI,CAAC;AAE/D,aAAS;AAAA,MACP,MAAM,IAAI;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAED,qBAAiB;AAAA,EACnB;AAEA,QAAM,QAAkC,OAAO,OAAO,aAAa;AACjE,UAAM,WAAW,MAAM;AAAA,MACrB,QAAQ,SAAS,UAAU,KAAK;AAAA,MAChC;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,MAC1C;AAAA,IACF;AAEA,sBAAkB,QAAQ;AAAA,EAC5B;AAEA,QAAM,SAAoC,OAAO,YAAY;AAC3D,UAAM,WAAW,MAAM;AAAA,MACrB,QAAQ,SAAS,UAAU,MAAM;AAAA,MACjC;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,OAAO;AAAA,MAC9B;AAAA,IACF;AAEA,sBAAkB,QAAQ;AAAA,EAC5B;AAEA,QAAM,SAAS,MAAM;AACnB,yBAAqB,IAAI;AACzB,iBAAa,WAAW,gBAAgB;AAExC,aAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAED,eAAW;AAAA,EACb;AAEA,QAAM,YAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,MAAM,SAAS,MAAM;AAAA,EACxB;AAEA,SAAO,4CAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;;;AExGA,IAAAA,gBAAiC;AAiBX,IAAAC,sBAAA;AATP,SAAR,UAA2B,EAAE,UAAU,WAAW,GAAmB;AAC1E,QAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ;AAElC,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,QAAQ,YAAY;AACnC,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,SAAS,MAAM,UAAU,CAAC;AAE9B,MAAI,QAAS,QAAO,6CAAC,SAAI,wBAAU;AACnC,MAAI,CAAC,KAAM,QAAO;AAElB,SAAO,6EAAG,UAAS;AACrB;;;ACnCA,IAAAC,gBAAgC;;;ACAhC,IAAAC,gBAAgC;AAiD1B,IAAAC,sBAAA;AA7CS,SAAR,sBAAuC;AAC5C,QAAM,EAAE,OAAO,IAAI,QAAQ;AAE3B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AAEtD,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,MAAM,QAAQ,OAAO,SAAS,OAAO,UAAU,MAAM;AAE3D,YAAM,SAAS,KAAK;AAAA,QAClB,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,MAChC,CAAC;AAED,cAAQ,IAAI;AAAA,IACd,SAAS,KAAU;AACjB,eAAS,KAAK,WAAW,yBAAyB;AAAA,IACpD;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV,OAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA;AAAA,QAGZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QAEtB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK,OAAO,UAAU;AAAA,gBACtB,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,cACL,OAAO;AAAA,cACP,SAAS;AAAA,cACT,cAAc;AAAA,cAEd,YAAY,OACR,6CACA;AAAA,cAEJ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,iBAAO,qBAAgB;AAAA;AAAA,QAC1B;AAAA,QAEC,QACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAGD,SACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AD/IM,IAAAC,sBAAA;AAVS,SAAR,cAA+B;AACpC,QAAM,EAAE,MAAM,IAAI,QAAQ;AAC1B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE;AAC3C,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAEhD,MAAI,WAAW;AACb,WACE,8CAAC,SAAI,OAAO,EAAE,WAAW,WAAW,GAClC;AAAA,mDAAC,uBAAoB;AAAA,MACrB;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,aAAa,KAAK;AAAA,UACjC,OAAO;AAAA,YACL,WAAW;AAAA,YACX,WAAW;AAAA,YACX,UAAU;AAAA,YACV,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,gBAAgB;AAAA,UAClB;AAAA,UACD;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAGA,QAAM,WAAW,OAAO,MAAuB;AAC7C,MAAE,eAAe;AACjB,kBAAc,IAAI;AAClB,aAAS,IAAI;AAEb,UAAM,eAAe,MAAM,KAAK;AAChC,UAAM,kBAAkB,SAAS,KAAK;AAEtC,QAAI,CAAC,gBAAgB,CAAC,iBAAiB;AACrC,eAAS,qCAAqC;AAC9C,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,MAAM,cAAc,eAAe;AAAA,IAC3C,SAAS,KAAU;AACjB,eAAS,KAAK,WAAW,cAAc;AAAA,IACzC,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA,QAEZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QAEtB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,cAC3C,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,aAAa,IAAI;AAAA,YAChC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,UAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,cAAc;AAAA,YAChB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,MAAK;AAAA,YACL,OAAO;AAAA,cACL,OAAO;AAAA,cACP,SAAS;AAAA,cACT,cAAc;AAAA,cAEd,YAAY,aACR,6CACA;AAAA,cAEJ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,uBAAa,kBAAkB;AAAA;AAAA,QAClC;AAAA,QAEC,SACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AElOA,IAAAC,gBAAgC;AAuD1B,IAAAC,sBAAA;AApDS,SAAR,eAAgC;AACrC,QAAM,EAAE,OAAO,IAAI,QAAQ;AAC3B,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,EAAE;AACnC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE;AAC3C,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AAEtD,QAAM,WAAW,OAAO,MAAuB;AAC7C,MAAE,eAAe;AACjB,kBAAc,IAAI;AAClB,aAAS,IAAI;AAEb,UAAM,eAAe,MAAM,KAAK;AAChC,UAAM,kBAAkB,SAAS,KAAK;AACtC,UAAM,cAAc,KAAK,KAAK;AAE9B,QAAI,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,aAAa;AACrD,eAAS,qCAAqC;AAC9C,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,OAAO,EAAE,MAAM,OAAO,SAAS,CAAC;AAAA,IACxC,SAAS,KAAU;AACjB,eAAS,KAAK,WAAW,eAAe;AAAA,IAC1C,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA;AAAA,QAGZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QAEtB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,cACvC,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,cAC3C,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,MAAK;AAAA,YACL,OAAO;AAAA,cACL,OAAO;AAAA,cACP,SAAS;AAAA,cACT,cAAc;AAAA,cACd,YAAY,aACR,6CACA;AAAA,cAEJ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,uBAAa,gBAAgB;AAAA;AAAA,QAChC;AAAA,QAEC,SACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":["import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,7 @@ import {
|
|
|
3
3
|
createContext,
|
|
4
4
|
useContext,
|
|
5
5
|
useMemo,
|
|
6
|
-
useState
|
|
7
|
-
useEffect
|
|
6
|
+
useState
|
|
8
7
|
} from "react";
|
|
9
8
|
|
|
10
9
|
// src/http.ts
|
|
@@ -73,56 +72,68 @@ async function httpJSON(url, opts = {}, withAuth = false) {
|
|
|
73
72
|
|
|
74
73
|
// src/AuthContext.tsx
|
|
75
74
|
import { jsx } from "react/jsx-runtime";
|
|
76
|
-
var
|
|
77
|
-
var AuthContext = createContext(
|
|
75
|
+
var USER_STORAGE_KEY = "afk_user";
|
|
76
|
+
var AuthContext = createContext(null);
|
|
78
77
|
function useAuth() {
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
78
|
+
const ctx = useContext(AuthContext);
|
|
79
|
+
if (!ctx) {
|
|
81
80
|
throw new Error("useAuth must be used inside AuthProvider");
|
|
82
81
|
}
|
|
83
|
-
return
|
|
82
|
+
return ctx;
|
|
84
83
|
}
|
|
85
|
-
function
|
|
86
|
-
const
|
|
87
|
-
return
|
|
84
|
+
function initState() {
|
|
85
|
+
const stored = localStorage.getItem(USER_STORAGE_KEY);
|
|
86
|
+
return {
|
|
87
|
+
user: stored ? JSON.parse(stored) : null,
|
|
88
|
+
loading: false
|
|
89
|
+
};
|
|
88
90
|
}
|
|
89
91
|
function AuthProvider({
|
|
90
92
|
config,
|
|
91
93
|
children
|
|
92
94
|
}) {
|
|
93
|
-
const [user,
|
|
94
|
-
const [loading, setLoading] = useState(true);
|
|
95
|
+
const [{ user, loading }, setState] = useState(initState);
|
|
95
96
|
const { baseURL, endpoints, onLoginSuccess, onLogout } = config;
|
|
96
97
|
const getToken = () => getStoredAccessToken();
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
const applyAuthResponse = (res) => {
|
|
99
|
+
setStoredAccessToken(res.accessToken);
|
|
100
|
+
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(res.user));
|
|
101
|
+
setState({
|
|
102
|
+
user: res.user,
|
|
103
|
+
loading: false
|
|
104
|
+
});
|
|
105
|
+
onLoginSuccess?.();
|
|
106
|
+
};
|
|
107
|
+
const login = async (email, password) => {
|
|
101
108
|
const response = await httpJSON(
|
|
102
|
-
makeURL(baseURL,
|
|
109
|
+
makeURL(baseURL, endpoints.login),
|
|
103
110
|
{
|
|
104
111
|
method: "POST",
|
|
105
|
-
body: JSON.stringify(
|
|
112
|
+
body: JSON.stringify({ email, password })
|
|
106
113
|
}
|
|
107
114
|
);
|
|
108
|
-
|
|
109
|
-
localStorage.setItem(USER_KEY, JSON.stringify(response.user));
|
|
110
|
-
setUser(response.user);
|
|
111
|
-
onLoginSuccess?.();
|
|
112
|
-
};
|
|
113
|
-
const login = async (email, password) => {
|
|
114
|
-
await runAuthRequest(endpoints.login, { email, password });
|
|
115
|
+
applyAuthResponse(response);
|
|
115
116
|
};
|
|
116
117
|
const signup = async (payload) => {
|
|
117
|
-
await
|
|
118
|
+
const response = await httpJSON(
|
|
119
|
+
makeURL(baseURL, endpoints.signup),
|
|
120
|
+
{
|
|
121
|
+
method: "POST",
|
|
122
|
+
body: JSON.stringify(payload)
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
applyAuthResponse(response);
|
|
118
126
|
};
|
|
119
127
|
const logout = () => {
|
|
120
128
|
setStoredAccessToken(null);
|
|
121
|
-
localStorage.removeItem(
|
|
122
|
-
|
|
129
|
+
localStorage.removeItem(USER_STORAGE_KEY);
|
|
130
|
+
setState({
|
|
131
|
+
user: null,
|
|
132
|
+
loading: false
|
|
133
|
+
});
|
|
123
134
|
onLogout?.();
|
|
124
135
|
};
|
|
125
|
-
const
|
|
136
|
+
const value = useMemo(
|
|
126
137
|
() => ({
|
|
127
138
|
user,
|
|
128
139
|
loading,
|
|
@@ -134,15 +145,15 @@ function AuthProvider({
|
|
|
134
145
|
}),
|
|
135
146
|
[user, loading, config]
|
|
136
147
|
);
|
|
137
|
-
return /* @__PURE__ */ jsx(AuthContext.Provider, { value
|
|
148
|
+
return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
|
|
138
149
|
}
|
|
139
150
|
|
|
140
151
|
// src/Protected.tsx
|
|
141
|
-
import { useEffect
|
|
152
|
+
import { useEffect } from "react";
|
|
142
153
|
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
143
154
|
function Protected({ children, redirectTo }) {
|
|
144
155
|
const { user, loading } = useAuth();
|
|
145
|
-
|
|
156
|
+
useEffect(() => {
|
|
146
157
|
if (!loading && !user && redirectTo) {
|
|
147
158
|
window.location.href = redirectTo;
|
|
148
159
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AuthContext.tsx","../src/http.ts","../src/Protected.tsx","../src/screens/LoginScreen.tsx","../src/screens/PasswordResetScreen.tsx","../src/screens/SignupScreen.tsx"],"sourcesContent":["import React, {\r\n createContext,\r\n useContext,\r\n useMemo,\r\n useState,\r\n useEffect,\r\n PropsWithChildren,\r\n} from \"react\";\r\n\r\nimport {\r\n AuthContextType,\r\n AuthProviderConfig,\r\n StandardAuthResponse,\r\n User,\r\n} from \"./types\";\r\n\r\nimport {\r\n httpJSON,\r\n makeURL,\r\n setStoredAccessToken,\r\n getStoredAccessToken,\r\n} from \"./http\";\r\n\r\nconst USER_KEY = \"afk_user\";\r\n\r\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\r\n\r\nexport function useAuth(): AuthContextType {\r\n const value = useContext(AuthContext);\r\n if (value === undefined) {\r\n throw new Error(\"useAuth must be used inside AuthProvider\");\r\n }\r\n return value;\r\n}\r\n\r\nfunction loadUser(): User | null {\r\n const raw = localStorage.getItem(USER_KEY);\r\n return raw ? JSON.parse(raw) : null;\r\n}\r\n\r\nexport function AuthProvider({\r\n config,\r\n children,\r\n}: PropsWithChildren<{ config: AuthProviderConfig }>) {\r\n const [user, setUser] = useState<User | null>(() => loadUser());\r\n const [loading, setLoading] = useState<boolean>(true);\r\n\r\n const { baseURL, endpoints, onLoginSuccess, onLogout } = config;\r\n\r\n const getToken = () => getStoredAccessToken();\r\n\r\n useEffect(() => {\r\n setLoading(false);\r\n }, []);\r\n\r\n const runAuthRequest = async (\r\n endpoint: string,\r\n body: unknown\r\n ): Promise<void> => {\r\n const response = await httpJSON<StandardAuthResponse>(\r\n makeURL(baseURL, endpoint),\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify(body),\r\n }\r\n );\r\n\r\n setStoredAccessToken(response.accessToken);\r\n localStorage.setItem(USER_KEY, JSON.stringify(response.user));\r\n setUser(response.user);\r\n\r\n onLoginSuccess?.();\r\n };\r\n\r\n const login: AuthContextType[\"login\"] = async (email, password) => {\r\n await runAuthRequest(endpoints.login, { email, password });\r\n };\r\n\r\n const signup: AuthContextType[\"signup\"] = async (payload) => {\r\n await runAuthRequest(endpoints.signup, payload);\r\n };\r\n\r\n const logout = () => {\r\n setStoredAccessToken(null);\r\n localStorage.removeItem(USER_KEY);\r\n setUser(null);\r\n onLogout?.();\r\n };\r\n\r\n const contextValue = useMemo<AuthContextType>(\r\n () => ({\r\n user,\r\n loading,\r\n login,\r\n signup,\r\n logout,\r\n getToken,\r\n config,\r\n }),\r\n [user, loading, config]\r\n );\r\n\r\n return (\r\n <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>\r\n );\r\n}\r\n","/*\r\n This file contains the low-level HTTP utilities used internally by\r\n auth-flow-kit to communicate with the backend.\r\n\r\n It provides:\r\n - makeURL: safely joins baseURL + endpoint path\r\n - getStoredAccessToken: reads the JWT from localStorage\r\n - setStoredAccessToken: stores/removes the JWT\r\n - httpJSON: wrapper around fetch with JSON + optional auth header\r\n\r\n NOTES FOR DEVELOPERS USING THE LIBRARY:\r\n You do NOT need to import or modify anything in this file.\r\n It is an internal helper used by the AuthProvider and auth screens.\r\n\r\n This keeps the library lightweight, predictable,\r\n and familiar to developers used to Redux Toolkit-style authentication.\r\n*/\r\n\r\nexport function makeURL(baseURL: string, path: string) {\r\n return `${baseURL.replace(/\\/$/, \"\")}${\r\n path.startsWith(\"/\") ? path : `/${path}`\r\n }`;\r\n}\r\n\r\nexport function getStoredAccessToken(): string | null {\r\n try {\r\n return localStorage.getItem(\"afk_access_token\");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function setStoredAccessToken(token: string | null) {\r\n try {\r\n if (token) localStorage.setItem(\"afk_access_token\", token);\r\n else localStorage.removeItem(\"afk_access_token\");\r\n } catch {\r\n // Gonna ignore storage errors (Safari private mode, etc.) for now, not exactly needed.\r\n }\r\n}\r\n\r\nexport async function httpJSON<T>(\r\n url: string,\r\n opts: RequestInit = {},\r\n withAuth = false\r\n): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n\r\n if (withAuth) {\r\n const tok = getStoredAccessToken();\r\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\r\n }\r\n\r\n const res = await fetch(url, {\r\n ...opts,\r\n headers: { ...headers, ...(opts.headers || {}) },\r\n });\r\n\r\n if (!res.ok) {\r\n let message = `Request failed (${res.status})`;\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n\r\n // Backend returned JSON error\r\n if (contentType.includes(\"application/json\")) {\r\n try {\r\n const data = await res.json();\r\n if (data?.message) message = data.message;\r\n } catch {\r\n // ignore JSON parse errors, cos not important to me now\r\n }\r\n }\r\n\r\n // Backend returned HTML (Express default error pages)\r\n if (contentType.includes(\"text/html\")) {\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n message =\r\n \"The forgot password endpoint you added in config.endpoints.forgot does not exist in your server. Please check and update your config.endpoints.forgot\";\r\n } else {\r\n message = \"Unexpected server error\";\r\n }\r\n }\r\n\r\n // Developer-only guidance\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n console.error(\r\n `[auth-flow-kit] Password reset endpoint not found.\r\n\r\n Expected a POST route matching:\r\n ${url}\r\n\r\n Fix this by either:\r\n - Adding the route on your backend, or\r\n - Updating config.endpoints.forgot`\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n}\r\n","\"use client\";\r\n\r\n/*\r\nProtected component\r\n\r\nWraps authenticated content and prevents rendering when unauthenticated.\r\n\r\nIMPORTANT:\r\nThis component does NOT hard-redirect by default.\r\nNavigation should be handled by the host application (router or state).\r\n\r\nIf redirectTo is provided AND the host app supports routing,\r\na redirect will occur.\r\n*/\r\n\r\nimport React, { useEffect } from \"react\";\r\nimport { useAuth } from \"./AuthContext\";\r\n\r\ntype ProtectedProps = {\r\n children: React.ReactNode;\r\n redirectTo?: string;\r\n};\r\n\r\nexport default function Protected({ children, redirectTo }: ProtectedProps) {\r\n const { user, loading } = useAuth();\r\n\r\n useEffect(() => {\r\n if (!loading && !user && redirectTo) {\r\n window.location.href = redirectTo;\r\n }\r\n }, [loading, user, redirectTo]);\r\n\r\n if (loading) return <div>Loading...</div>;\r\n if (!user) return null;\r\n\r\n return <>{children}</>;\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport PasswordResetScreen from \"./PasswordResetScreen\";\r\n\r\nexport default function LoginScreen() {\r\n const { login } = useAuth();\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [showReset, setShowReset] = useState(false);\r\n\r\n if (showReset) {\r\n return (\r\n <div style={{ animation: \"fade .2s\" }}>\r\n <PasswordResetScreen />\r\n <p\r\n onClick={() => setShowReset(false)}\r\n style={{\r\n marginTop: 16,\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n textDecoration: \"underline\",\r\n }}\r\n >\r\n Back to login\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Submit\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await login(trimmedEmail, trimmedPassword);\r\n } catch (err: any) {\r\n setError(err?.message || \"Login failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Welcome Back 👋\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 10 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <p\r\n onClick={() => setShowReset(true)}\r\n style={{\r\n textAlign: \"right\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n >\r\n Forgot password?\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Signing in...\" : \"Sign in\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport { httpJSON, makeURL } from \"../http\";\r\n\r\nexport default function PasswordResetScreen() {\r\n const { config } = useAuth();\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [sent, setSent] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const requestReset = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n try {\r\n const url = makeURL(config.baseURL, config.endpoints.forgot);\r\n\r\n await httpJSON(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email }),\r\n });\r\n\r\n setSent(true);\r\n } catch (err: any) {\r\n setError(err?.message || \"Failed to request reset\");\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={requestReset}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.25s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Reset Password 🔑\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: sent ? \"-18px\" : \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"90%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: sent\r\n ? \"linear-gradient(90deg, #7aff9d, #34c759)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.3s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {sent ? \"Link Sent ✔\" : \"Send reset link\"}\r\n </button>\r\n\r\n {sent && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"#2ecc71\",\r\n textAlign: \"center\",\r\n fontSize: 15,\r\n fontWeight: 600,\r\n }}\r\n >\r\n Check your email for reset instructions.\r\n </p>\r\n )}\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\n\r\nexport default function SignupScreen() {\r\n const { signup } = useAuth();\r\n const [name, setName] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n const trimmedName = name.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword || !trimmedName) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await signup({ name, email, password });\r\n } catch (err: any) {\r\n setError(err?.message || \"Signup failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Create Account ✨\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Name\r\n </label>\r\n\r\n <input\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n placeholder=\"Your name\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Creating...\" : \"Create account\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n"],"mappings":"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","names":["useEffect","jsx","useEffect","useState","useState","jsx","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/AuthContext.tsx","../src/http.ts","../src/Protected.tsx","../src/screens/LoginScreen.tsx","../src/screens/PasswordResetScreen.tsx","../src/screens/SignupScreen.tsx"],"sourcesContent":["import React, {\r\n createContext,\r\n useContext,\r\n useMemo,\r\n useState,\r\n PropsWithChildren,\r\n} from \"react\";\r\n\r\nimport {\r\n AuthContextType,\r\n AuthProviderConfig,\r\n StandardAuthResponse,\r\n User,\r\n} from \"./types\";\r\n\r\nimport {\r\n httpJSON,\r\n makeURL,\r\n setStoredAccessToken,\r\n getStoredAccessToken,\r\n} from \"./http\";\r\n\r\nconst USER_STORAGE_KEY = \"afk_user\";\r\n\r\ntype AuthState = {\r\n user: User | null;\r\n loading: boolean;\r\n};\r\n\r\nconst AuthContext = createContext<AuthContextType | null>(null);\r\n\r\nexport function useAuth(): AuthContextType {\r\n const ctx = useContext(AuthContext);\r\n if (!ctx) {\r\n throw new Error(\"useAuth must be used inside AuthProvider\");\r\n }\r\n return ctx;\r\n}\r\n\r\nfunction initState(): AuthState {\r\n const stored = localStorage.getItem(USER_STORAGE_KEY);\r\n return {\r\n user: stored ? JSON.parse(stored) : null,\r\n loading: false,\r\n };\r\n}\r\n\r\nexport function AuthProvider({\r\n config,\r\n children,\r\n}: PropsWithChildren<{ config: AuthProviderConfig }>) {\r\n const [{ user, loading }, setState] = useState<AuthState>(initState);\r\n\r\n const { baseURL, endpoints, onLoginSuccess, onLogout } = config;\r\n\r\n const getToken = () => getStoredAccessToken();\r\n\r\n const applyAuthResponse = (res: StandardAuthResponse) => {\r\n setStoredAccessToken(res.accessToken);\r\n localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(res.user));\r\n\r\n setState({\r\n user: res.user,\r\n loading: false,\r\n });\r\n\r\n onLoginSuccess?.();\r\n };\r\n\r\n const login: AuthContextType[\"login\"] = async (email, password) => {\r\n const response = await httpJSON<StandardAuthResponse>(\r\n makeURL(baseURL, endpoints.login),\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify({ email, password }),\r\n }\r\n );\r\n\r\n applyAuthResponse(response);\r\n };\r\n\r\n const signup: AuthContextType[\"signup\"] = async (payload) => {\r\n const response = await httpJSON<StandardAuthResponse>(\r\n makeURL(baseURL, endpoints.signup),\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify(payload),\r\n }\r\n );\r\n\r\n applyAuthResponse(response);\r\n };\r\n\r\n const logout = () => {\r\n setStoredAccessToken(null);\r\n localStorage.removeItem(USER_STORAGE_KEY);\r\n\r\n setState({\r\n user: null,\r\n loading: false,\r\n });\r\n\r\n onLogout?.();\r\n };\r\n\r\n const value = useMemo<AuthContextType>(\r\n () => ({\r\n user,\r\n loading,\r\n login,\r\n signup,\r\n logout,\r\n getToken,\r\n config,\r\n }),\r\n [user, loading, config]\r\n );\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n","/*\r\n This file contains the low-level HTTP utilities used internally by\r\n auth-flow-kit to communicate with the backend.\r\n\r\n It provides:\r\n - makeURL: safely joins baseURL + endpoint path\r\n - getStoredAccessToken: reads the JWT from localStorage\r\n - setStoredAccessToken: stores/removes the JWT\r\n - httpJSON: wrapper around fetch with JSON + optional auth header\r\n\r\n NOTES FOR DEVELOPERS USING THE LIBRARY:\r\n You do NOT need to import or modify anything in this file.\r\n It is an internal helper used by the AuthProvider and auth screens.\r\n\r\n This keeps the library lightweight, predictable,\r\n and familiar to developers used to Redux Toolkit-style authentication.\r\n*/\r\n\r\nexport function makeURL(baseURL: string, path: string) {\r\n return `${baseURL.replace(/\\/$/, \"\")}${\r\n path.startsWith(\"/\") ? path : `/${path}`\r\n }`;\r\n}\r\n\r\nexport function getStoredAccessToken(): string | null {\r\n try {\r\n return localStorage.getItem(\"afk_access_token\");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function setStoredAccessToken(token: string | null) {\r\n try {\r\n if (token) localStorage.setItem(\"afk_access_token\", token);\r\n else localStorage.removeItem(\"afk_access_token\");\r\n } catch {\r\n // Gonna ignore storage errors (Safari private mode, etc.) for now, not exactly needed.\r\n }\r\n}\r\n\r\nexport async function httpJSON<T>(\r\n url: string,\r\n opts: RequestInit = {},\r\n withAuth = false\r\n): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n\r\n if (withAuth) {\r\n const tok = getStoredAccessToken();\r\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\r\n }\r\n\r\n const res = await fetch(url, {\r\n ...opts,\r\n headers: { ...headers, ...(opts.headers || {}) },\r\n });\r\n\r\n if (!res.ok) {\r\n let message = `Request failed (${res.status})`;\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n\r\n // Backend returned JSON error\r\n if (contentType.includes(\"application/json\")) {\r\n try {\r\n const data = await res.json();\r\n if (data?.message) message = data.message;\r\n } catch {\r\n // ignore JSON parse errors, cos not important to me now\r\n }\r\n }\r\n\r\n // Backend returned HTML (Express default error pages)\r\n if (contentType.includes(\"text/html\")) {\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n message =\r\n \"The forgot password endpoint you added in config.endpoints.forgot does not exist in your server. Please check and update your config.endpoints.forgot\";\r\n } else {\r\n message = \"Unexpected server error\";\r\n }\r\n }\r\n\r\n // Developer-only guidance\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n console.error(\r\n `[auth-flow-kit] Password reset endpoint not found.\r\n\r\n Expected a POST route matching:\r\n ${url}\r\n\r\n Fix this by either:\r\n - Adding the route on your backend, or\r\n - Updating config.endpoints.forgot`\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n}\r\n","\"use client\";\r\n\r\n/*\r\nProtected component\r\n\r\nWraps authenticated content and prevents rendering when unauthenticated.\r\n\r\nIMPORTANT:\r\nThis component does NOT hard-redirect by default.\r\nNavigation should be handled by the host application (router or state).\r\n\r\nIf redirectTo is provided AND the host app supports routing,\r\na redirect will occur.\r\n*/\r\n\r\nimport React, { useEffect } from \"react\";\r\nimport { useAuth } from \"./AuthContext\";\r\n\r\ntype ProtectedProps = {\r\n children: React.ReactNode;\r\n redirectTo?: string;\r\n};\r\n\r\nexport default function Protected({ children, redirectTo }: ProtectedProps) {\r\n const { user, loading } = useAuth();\r\n\r\n useEffect(() => {\r\n if (!loading && !user && redirectTo) {\r\n window.location.href = redirectTo;\r\n }\r\n }, [loading, user, redirectTo]);\r\n\r\n if (loading) return <div>Loading...</div>;\r\n if (!user) return null;\r\n\r\n return <>{children}</>;\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport PasswordResetScreen from \"./PasswordResetScreen\";\r\n\r\nexport default function LoginScreen() {\r\n const { login } = useAuth();\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [showReset, setShowReset] = useState(false);\r\n\r\n if (showReset) {\r\n return (\r\n <div style={{ animation: \"fade .2s\" }}>\r\n <PasswordResetScreen />\r\n <p\r\n onClick={() => setShowReset(false)}\r\n style={{\r\n marginTop: 16,\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n textDecoration: \"underline\",\r\n }}\r\n >\r\n Back to login\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Submit\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await login(trimmedEmail, trimmedPassword);\r\n } catch (err: any) {\r\n setError(err?.message || \"Login failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Welcome Back 👋\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 10 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <p\r\n onClick={() => setShowReset(true)}\r\n style={{\r\n textAlign: \"right\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n >\r\n Forgot password?\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Signing in...\" : \"Sign in\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport { httpJSON, makeURL } from \"../http\";\r\n\r\nexport default function PasswordResetScreen() {\r\n const { config } = useAuth();\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [sent, setSent] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const requestReset = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n try {\r\n const url = makeURL(config.baseURL, config.endpoints.forgot);\r\n\r\n await httpJSON(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email }),\r\n });\r\n\r\n setSent(true);\r\n } catch (err: any) {\r\n setError(err?.message || \"Failed to request reset\");\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={requestReset}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.25s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Reset Password 🔑\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: sent ? \"-18px\" : \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"90%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: sent\r\n ? \"linear-gradient(90deg, #7aff9d, #34c759)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.3s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {sent ? \"Link Sent ✔\" : \"Send reset link\"}\r\n </button>\r\n\r\n {sent && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"#2ecc71\",\r\n textAlign: \"center\",\r\n fontSize: 15,\r\n fontWeight: 600,\r\n }}\r\n >\r\n Check your email for reset instructions.\r\n </p>\r\n )}\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\n\r\nexport default function SignupScreen() {\r\n const { signup } = useAuth();\r\n const [name, setName] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n const trimmedName = name.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword || !trimmedName) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await signup({ name, email, password });\r\n } catch (err: any) {\r\n setError(err?.message || \"Signup failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Create Account ✨\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Name\r\n </label>\r\n\r\n <input\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n placeholder=\"Your name\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Creating...\" : \"Create account\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n"],"mappings":"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","names":["jsx","useState","useState","jsx","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState"]}
|