Skip to content

Instantly share code, notes, and snippets.

@nicolasmelo1
Created January 25, 2024 18:03
Show Gist options
  • Save nicolasmelo1/a78fbe6030e6cd86bfd61478d672e4e7 to your computer and use it in GitHub Desktop.
Save nicolasmelo1/a78fbe6030e6cd86bfd61478d672e4e7 to your computer and use it in GitHub Desktop.
"use client";
import cookieParser from "./default";
const cookie = cookieParser(
typeof document === "undefined" ? "" : document?.cookie || ""
);
export default cookie;
const savedCookies = new Map<
string,
{
expires?: Date;
maxAge?: number;
value: string;
samesite?: "strict" | "lax" | "none";
secure?: boolean;
path?: string;
}
>();
export default function cookies(cookiesString?: string) {
function parseCookie() {
if (typeof document === "undefined") return;
if (!document.cookie && !cookiesString) return;
if (document.cookie) console.log("document.cookie", document.cookie);
const cookiesToParse = (cookiesString || document.cookie).toLowerCase();
const cookiesToParseArray = cookiesToParse.split("; ");
let currentCookie = undefined;
while (cookiesToParseArray.length > 0) {
const currentCookieData = cookiesToParseArray.shift() as string;
const isExpires = currentCookieData.startsWith("expires");
const isMaxAge = currentCookieData.startsWith("max-age");
const isSameSite = currentCookieData.startsWith("samesite");
const isSecure = currentCookieData.startsWith("secure");
const isPath = currentCookieData.startsWith("path");
const currentSavedCookieData = currentCookie
? savedCookies.get(currentCookie)
: {};
if (isExpires) {
const [, expires] = currentCookieData.split("=");
if (currentCookie && expires)
savedCookies.set(currentCookie, {
...currentSavedCookieData,
expires: new Date(expires),
} as any);
continue;
}
if (isMaxAge) {
const [, maxAge] = currentCookieData.split("=");
if (currentCookie && maxAge)
savedCookies.set(currentCookie, {
...currentSavedCookieData,
maxAge: parseInt(maxAge),
} as any);
continue;
}
if (isSameSite) {
const [, samesite] = currentCookieData.split("=");
if (currentCookie && samesite)
savedCookies.set(currentCookie, {
...currentSavedCookieData,
samesite: samesite as any,
} as any);
continue;
}
if (isSecure) {
if (currentCookie)
savedCookies.set(currentCookie, {
...currentSavedCookieData,
secure: true,
} as any);
continue;
}
if (isPath) {
const [, path] = currentCookieData.split("=");
if (currentCookie && path)
savedCookies.set(currentCookie, {
...currentSavedCookieData,
path,
} as any);
continue;
}
const [cookieKey, cookieValue] = currentCookieData.split("=");
currentCookie = cookieKey;
savedCookies.set(cookieKey, { value: cookieValue });
continue;
}
}
function toString() {
return Array.from(savedCookies.entries())
.map(
([key, value]) =>
`${key}=${value.value}${
value.expires ? `; expires=${value.expires}` : ""
}${value.maxAge ? `; max-age=${value.maxAge}` : ""}${
value.secure ? `; secure` : ""
}${value.path ? `; path=${value.path}` : ""}${
value.samesite ? `; samesite=${value.samesite}` : ""
}`
)
.join("; ");
}
parseCookie();
return {
get(key: string) {
const savedCookie = savedCookies.get(key);
if (!savedCookie) return;
const decoded = structuredClone(savedCookie);
decoded.value = decodeURIComponent(decoded.value);
return decoded;
},
set(key: string, value: string) {
const encoded = encodeURIComponent(value);
const existingCookie = savedCookies.get(key);
if (existingCookie) existingCookie.value = encoded;
else savedCookies.set(key, { value: encoded });
for (const [savedCookieKey, value] of Array.from(
savedCookies.entries()
)) {
document.cookie = `${savedCookieKey}=${value.value}`;
}
console.log("setCookie", document.cookie);
},
has(key: string) {
return savedCookies.has(key);
},
delete(key: string) {
savedCookies.delete(key);
for (const [savedCookieKey, value] of Array.from(
savedCookies.entries()
)) {
if (key === savedCookieKey)
document.cookie = `${savedCookieKey}=${value}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
else document.cookie = `${savedCookieKey}=${value}`;
}
},
toString,
};
}
"use server";
import { cookies } from "next/headers";
import cookieParser from "./default";
const cookie = cookieParser(cookies().toString());
export default cookie;
import { useCallback, useState } from "react";
import { serverCookies, clientCookies } from "../utils/cookies";
const clientOrServerCookies =
typeof window === "undefined" ? serverCookies : clientCookies;
export default function useCookieStorageState<TValue>(
key: string,
defaultValue?: TValue
) {
const [state, _setState] = useState<TValue>(() => {
if (clientOrServerCookies.has(key)) {
const valueInCookies = clientOrServerCookies.get(key);
const isValidValueInLocalStorage =
valueInCookies?.value &&
[undefined, null, ""].includes(valueInCookies.value) === false;
console.log("valueInCookies?.value", valueInCookies?.value);
if (isValidValueInLocalStorage)
return JSON.parse(valueInCookies?.value as string);
}
console.log(
"reaching here",
key,
typeof defaultValue === "function" ? defaultValue() : defaultValue
);
return typeof defaultValue === "function" ? defaultValue() : defaultValue;
});
const setState = useCallback(
(value: TValue) => {
_setState(value);
clientOrServerCookies.set(key, JSON.stringify(value));
},
[_setState, key]
);
return [state, setState] as const;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment