Instantly share code, notes, and snippets.
Created
January 25, 2024 18:03
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save nicolasmelo1/a78fbe6030e6cd86bfd61478d672e4e7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use client"; | |
import cookieParser from "./default"; | |
const cookie = cookieParser( | |
typeof document === "undefined" ? "" : document?.cookie || "" | |
); | |
export default cookie; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use server"; | |
import { cookies } from "next/headers"; | |
import cookieParser from "./default"; | |
const cookie = cookieParser(cookies().toString()); | |
export default cookie; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { 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