mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-24 17:03:55 +10:00
108 lines
2.8 KiB
TypeScript
108 lines
2.8 KiB
TypeScript
import Cookie from "js-cookie";
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
|
type CookieAttributes = NonNullable<Parameters<typeof Cookie.set>[2]>;
|
|
|
|
type SharedCookieOptions = {
|
|
domain?: CookieAttributes["domain"];
|
|
partitioned?: boolean;
|
|
path?: CookieAttributes["path"];
|
|
sameSite?: CookieAttributes["sameSite"];
|
|
secure?: CookieAttributes["secure"];
|
|
};
|
|
|
|
export type UseCookieOptions = SharedCookieOptions & {
|
|
expires?: CookieAttributes["expires"];
|
|
};
|
|
export type UseCookieRemoveOptions = SharedCookieOptions;
|
|
|
|
export const DEFAULT_COOKIE_ATTRIBUTES = {
|
|
path: "/",
|
|
secure: true,
|
|
sameSite: "lax",
|
|
} as const satisfies UseCookieRemoveOptions;
|
|
|
|
const canUseCookies = () => typeof document !== "undefined";
|
|
|
|
const getCookie = (name: string) => {
|
|
if (!canUseCookies()) return null;
|
|
return Cookie.get(name) ?? null;
|
|
};
|
|
|
|
const compactCookieOptions = ({
|
|
domain,
|
|
expires,
|
|
partitioned,
|
|
path,
|
|
sameSite,
|
|
secure,
|
|
}: UseCookieOptions): CookieAttributes => ({
|
|
...(domain !== undefined && { domain }),
|
|
...(expires !== undefined && { expires }),
|
|
...(partitioned !== undefined && { partitioned }),
|
|
...(path !== undefined && { path }),
|
|
...(sameSite !== undefined && { sameSite }),
|
|
...(secure !== undefined && { secure }),
|
|
});
|
|
|
|
const resolveCookieOptions = (options?: UseCookieOptions): CookieAttributes => {
|
|
return {
|
|
...DEFAULT_COOKIE_ATTRIBUTES,
|
|
...(options && compactCookieOptions(options)),
|
|
};
|
|
};
|
|
|
|
const resolveRemoveOptions = (options?: UseCookieRemoveOptions): CookieAttributes => {
|
|
return {
|
|
...DEFAULT_COOKIE_ATTRIBUTES,
|
|
...(options && compactCookieOptions(options)),
|
|
};
|
|
};
|
|
|
|
export function useCookie(
|
|
name: string,
|
|
defaultValue?: string,
|
|
defaultOptions?: UseCookieOptions,
|
|
): readonly [
|
|
string | null,
|
|
(value: string, options?: UseCookieOptions) => void,
|
|
(options?: UseCookieRemoveOptions) => void,
|
|
] {
|
|
const initialValue = useMemo(() => getCookie(name) ?? defaultValue ?? null, [name, defaultValue]);
|
|
const [value, setValue] = useState<string | null>(initialValue);
|
|
|
|
useEffect(() => {
|
|
const cookie = getCookie(name);
|
|
let nextValue: string | null;
|
|
|
|
if (cookie !== null) {
|
|
nextValue = cookie;
|
|
} else if (defaultValue === undefined) {
|
|
nextValue = null;
|
|
} else {
|
|
if (canUseCookies()) Cookie.set(name, defaultValue, resolveCookieOptions(defaultOptions));
|
|
nextValue = defaultValue;
|
|
}
|
|
|
|
setValue(nextValue);
|
|
}, [name, defaultValue, defaultOptions]);
|
|
|
|
const updateCookie = useCallback(
|
|
(nextValue: string, options?: UseCookieOptions) => {
|
|
if (canUseCookies()) Cookie.set(name, nextValue, resolveCookieOptions(options));
|
|
setValue(nextValue);
|
|
},
|
|
[name],
|
|
);
|
|
|
|
const deleteCookie = useCallback(
|
|
(options?: UseCookieRemoveOptions) => {
|
|
if (canUseCookies()) Cookie.remove(name, resolveRemoveOptions(options));
|
|
setValue(null);
|
|
},
|
|
[name],
|
|
);
|
|
|
|
return [value, updateCookie, deleteCookie] as const;
|
|
}
|