diff --git a/lib/auth/constants.ts b/lib/auth/constants.ts index 9e0043aa..f397c836 100644 --- a/lib/auth/constants.ts +++ b/lib/auth/constants.ts @@ -1,5 +1,4 @@ // constants.ts TS-Doc? - export const providers = [ { id: 'email', name: 'Email', type: 'email' }, { id: 'github', name: 'GitHub', type: 'oauth' }, @@ -27,17 +26,25 @@ const methods = { }, getCsrf: async () => { try { - const response = await fetch(`${process.env.NEXT_PUBLIC_NEXUS_HOST}/api/auth/csrf`); + const response = await fetch(`${process.env.NEXT_PUBLIC_NEXUS_HOST}/api/auth/csrf`, { credentials: 'include' }); const csrf = await response.json(); return csrf.csrfToken; } catch (e) { console.error(e); } }, - getSession: async () => { + getSession: async (params = { cookies: '' }) => { try { - const response = await fetch(`${process.env.NEXT_PUBLIC_NEXUS_HOST}/api/auth/session`); - const session = await response.json(); + const response = await fetch(`${process.env.NEXT_PUBLIC_NEXUS_HOST}/api/auth/session`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Cookie: params?.cookies, + }, + credentials: 'include', + }); + const session = await response?.json(); return session; } catch (e) { console.error(e); diff --git a/lib/model/decorators/hypnos-public-decorator.ts b/lib/model/decorators/hypnos-public-decorator.ts index 2c81049e..8900b975 100644 --- a/lib/model/decorators/hypnos-public-decorator.ts +++ b/lib/model/decorators/hypnos-public-decorator.ts @@ -6,7 +6,7 @@ import type { ICard } from '@dreampipcom/oneiros'; /* private */ const decorateListing = (listing: Record, uMeta: any): ICard => { const decd: ICard = { - id: `list__card--${listing?.title?.es}`, + id: `${listing.id}`, className: '', title: `${listing?.title?.es}`, where: `${listing?.location?.name}`, @@ -16,18 +16,17 @@ const decorateListing = (listing: Record, uMeta: any): ICard => { link: 'https://www.dreampip.com', badgeLink: 'https://www.dreampip.com', rating: '3/5', - selected: false, + selected: uMeta?.favorites?.includes(listing.id), } as Record as ICard; // decd.favorite = undefined; // if (uMeta?.rickmorty?.favorites?.characters?.includes(character?.id)) decd.favorite = true; // else decd.favorite = false; - return decd; }; /* public */ -export const decorateHypnosPublicListings = async (listings: Record[], uid: string): Promise => { +export const decorateHypnosPublicListings = async (listings: Record[], uMeta: any): Promise => { // const uMeta: UserSchema = await getUserMeta({ email: uid }); - const decd: ICard[] = listings?.map((card) => decorateListing(card, { email: uid })); + const decd: ICard[] = listings?.map((card) => decorateListing(card, uMeta)); return decd; }; diff --git a/lib/model/decorators/rm-decorator.ts b/lib/model/decorators/rm-decorator.ts index 160068f0..358d8e3e 100644 --- a/lib/model/decorators/rm-decorator.ts +++ b/lib/model/decorators/rm-decorator.ts @@ -1,20 +1,33 @@ /* eslint @typescript-eslint/consistent-type-assertions:0 */ // rm-decorator.ts input: rm meta; output: decorated rm meta; 'use server'; -import type { IDCharacter, INCharacter } from '@types'; +import type { ICard } from '@dreampipcom/oneiros'; +import type { INCharacter } from '@types'; /* private */ -const decorateCharacter = (character: INCharacter, uMeta: any): IDCharacter => { - const decd: IDCharacter = { ...character }; - decd.favorite = undefined; - if (uMeta?.rickmorty?.favorites?.characters?.includes(character?.id)) decd.favorite = true; - else decd.favorite = false; +const decorateCharacter = (character: INCharacter, uMeta: any): ICard => { + const decd: ICard = { + id: `list__char--${character?.name}`, + className: '', + // onLike: () => {}, + title: `${character?.name}`, + where: `${character?.location?.name}`, + when: `${character?.status}`, + image: `${character?.image}`, + price: '299€', + link: 'https://www.dreampip.com', + badgeLink: 'https://www.dreampip.com', + rating: '3/5', + selected: uMeta?.favorites?.includes(character.id), + } as Record as ICard; + return decd; }; /* public */ -export const decorateRMCharacters = async (characters: INCharacter[], uid: string): Promise => { +export const decorateRMCharacters = async (characters: INCharacter[], uMeta: any): Promise => { // const uMeta: UserSchema = await getUserMeta({ email: uid }); - const decd: IDCharacter[] = characters.map((char) => decorateCharacter(char, { email: uid })); + const decd: ICard[] = characters.map((char) => decorateCharacter(char, uMeta)); + console.log({ characters, uMeta, decd }); return decd; }; diff --git a/lib/model/interfaces/index.ts b/lib/model/interfaces/index.ts index cf885fd6..239235e1 100644 --- a/lib/model/interfaces/index.ts +++ b/lib/model/interfaces/index.ts @@ -11,3 +11,4 @@ export { DATABASE_STRING, DATABASE_USERS_STRING, DATABASE_ORGS_STRING } from './ export { getCharacters as getRMCharacters } from './services/rickmorty/rm-connector'; export { getPublicListings as getHypnosPublicListings } from './services/hypnos/public/hypnos-public-connector'; +export { updateUserFavoriteListings } from './services/hypnos/private/hypnos-private-user-connector'; diff --git a/lib/model/interfaces/services/hypnos/private/hypnos-private-user-connector.ts b/lib/model/interfaces/services/hypnos/private/hypnos-private-user-connector.ts new file mode 100644 index 00000000..09caf630 --- /dev/null +++ b/lib/model/interfaces/services/hypnos/private/hypnos-private-user-connector.ts @@ -0,0 +1,55 @@ +// hypnos-private-user-like-listing.ts +// rm-connector.ts +// to-do: use prisma for graph type +import type { ICard } from '@dreampipcom/oneiros'; + +import { cookies } from 'next/headers'; +// const CHARS = ` +// query { +// characters() { +// info { +// count +// } +// results { +// id +// name +// status +// origin { +// name +// } +// location { +// name +// } +// image +// } +// } +// } +// `; + +async function fetchREPL({ paramsStr, method, listings }: any) { + // to-do: might be worth hardcoding the api in case too many middleware requests are billed + try { + const cookieStore = cookies(); + const cookieString = cookieStore.toString(); + const payload = JSON.stringify({ listings }); + const req = await fetch(`${process.env.API_HOST}/api/v1/user${paramsStr}`, { + method, + headers: { + 'Content-Type': 'application/json', + cookies: cookieString, + }, + body: payload, + credentials: 'include', + }); + const json = await req.json(); + return json; + } catch (e) { + return { ok: false, status: 500, message: JSON.stringify(e), data: [] }; + } +} + +export const updateUserFavoriteListings: ({ paramsStr }: any) => Promise = async ({ listings }) => { + const entries = await fetchREPL({ paramsStr: '', method: 'PATCH', listings }); + const response = entries?.data; + return response; +}; diff --git a/lib/model/interfaces/services/hypnos/private/index.ts b/lib/model/interfaces/services/hypnos/private/index.ts new file mode 100644 index 00000000..3ac4cf37 --- /dev/null +++ b/lib/model/interfaces/services/hypnos/private/index.ts @@ -0,0 +1,2 @@ +// index.ts +export { updateUserFavoriteListings } from './hypnos-private-user-connector'; diff --git a/lib/model/interfaces/services/index.ts b/lib/model/interfaces/services/index.ts index 0e172f22..2c7dfab2 100644 --- a/lib/model/interfaces/services/index.ts +++ b/lib/model/interfaces/services/index.ts @@ -1,10 +1,12 @@ // index.ts import * as rickmorty from './rickmorty'; import * as hypnosPublic from './hypnos/public'; +import * as hypnosPrivate from './hypnos/private'; const services = { rickmorty, hypnosPublic, + hypnosPrivate, }; export default services; diff --git a/lib/state/context-auth.ts b/lib/state/context-auth.ts index 809192f8..923c8d88 100644 --- a/lib/state/context-auth.ts +++ b/lib/state/context-auth.ts @@ -6,6 +6,7 @@ import { createContext } from 'react'; export const AuthContext = createContext({ authd: false, name: '', + user: {}, setter: undefined, history: [], }); diff --git a/lib/types/contexts.d.ts b/lib/types/contexts.d.ts index b861f564..f018950a 100644 --- a/lib/types/contexts.d.ts +++ b/lib/types/contexts.d.ts @@ -9,7 +9,7 @@ export interface History { } export interface INCharacter { - id: number; + id: string; name: string; status: string; image: string; @@ -31,7 +31,7 @@ export interface IAuthContext extends History { authd?: boolean; name?: string; email?: string; - meta?: UserSchema; + user?: UserSchema; } export interface IGlobalContext extends History { diff --git a/lib/types/users.d.ts b/lib/types/users.d.ts index 1d9ce442..12691109 100644 --- a/lib/types/users.d.ts +++ b/lib/types/users.d.ts @@ -9,10 +9,10 @@ export interface UserDecoration { /* temp optional */ username?: string; bio?: string; - organizations: DUserOrgAmbiRelation[]; - rickmorty: { - favorites: { - characters: INCharacter['id'][]; + organizations?: DUserOrgAmbiRelation[]; + rickmorty?: { + favorites?: { + characters?: INCharacter['id'][]; }; }; } diff --git a/package-lock.json b/package-lock.json index 3f1ad092..d9a6fc76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "HPL3-ECO-AND-ANC", "dependencies": { - "@dreampipcom/oneiros": "0.0.5", + "@dreampipcom/oneiros": "0.0.6", "@sentry/nextjs": "7.118.0", "next": "14.2.4", "react": "18", @@ -376,9 +376,9 @@ } }, "node_modules/@dreampipcom/oneiros": { - "version": "0.0.5", - "resolved": "https://npm.pkg.github.com/download/@dreampipcom/oneiros/0.0.5/d2b1caa79fef7bc3611e75eecf4e5ccfbf9b459f", - "integrity": "sha512-mKvffZ8JmW9z46Pe23ZIEYlBmEYxYT2aS79izCLWaSj2/A6isD7Ls9GPsQ8hKkIILnc+6NpSyxVbtDVbuFMKeg==", + "version": "0.0.6", + "resolved": "https://npm.pkg.github.com/download/@dreampipcom/oneiros/0.0.6/c7527480bffd092bf71e4a87c53896d8c24750fe", + "integrity": "sha512-FWVq+ZoICpQc/krdPxdbllzAr7w59xa3aza7Fvkwcqyw/0HNtzwIjuUfHhGLQBzoI/FjiVeXJSq0J3SetrWP0w==", "license": "HPL3-ECO-AND-ANC", "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "4.9.5" diff --git a/package.json b/package.json index eaf26769..20a2a3d3 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "prepare": "husky" }, "dependencies": { - "@dreampipcom/oneiros": "0.0.5", + "@dreampipcom/oneiros": "0.0.6", "@sentry/nextjs": "7.118.0", "next": "14.2.4", "react": "18", diff --git a/src/app/components/client/blocks/topnav-view.tsx b/src/app/components/client/blocks/topnav-view.tsx index ef538874..6aa9e993 100644 --- a/src/app/components/client/blocks/topnav-view.tsx +++ b/src/app/components/client/blocks/topnav-view.tsx @@ -43,9 +43,10 @@ export const VTopNav = ({ user }: VTopNavProps) => { if (!isUserLoaded && _user && !initd.current) { loadUser({ authd: true, - name: user?.name || user?.email, - avatar: user?.image, - email: user?.email, + name: _user?.name || _user?.email, + avatar: _user?.image, + email: _user?.email, + user: _user, }); initd.current = true; } diff --git a/src/app/components/client/elements/hypnos-list-view.tsx b/src/app/components/client/elements/hypnos-list-view.tsx index 8898fa83..5de78dd1 100644 --- a/src/app/components/client/elements/hypnos-list-view.tsx +++ b/src/app/components/client/elements/hypnos-list-view.tsx @@ -22,7 +22,7 @@ type VHPNPListingProps = VListingListProps; export const VHPNPList = ({ listings }: VHPNPListingProps) => { const hypnosPublicContext = useContext(HypnosPublicContext); - const { authd, email } = useContext(AuthContext); + const { authd, email, user } = useContext(AuthContext); const globalContext = useContext(GlobalContext); const { theme } = globalContext; @@ -37,9 +37,9 @@ export const VHPNPList = ({ listings }: VHPNPListingProps) => { const dispatchAddToFavorites = async (cid?: number) => { const func = async (payload: IDPayload) => { - await addToFavorites(); + await addToFavorites({ listings: [cid] }); const op_2 = await loadHypnosPublicListings(); - loadListings({ characters: op_2 }); + loadListings({ listings: op_2 }); }; favListing({ email, cid }, func); }; @@ -77,7 +77,7 @@ export const VHPNPList = ({ listings }: VHPNPListingProps) => { if (authd) { return (
- +
); } diff --git a/src/app/components/client/elements/rm-list-view.tsx b/src/app/components/client/elements/rm-list-view.tsx index e5f44081..fe94447e 100644 --- a/src/app/components/client/elements/rm-list-view.tsx +++ b/src/app/components/client/elements/rm-list-view.tsx @@ -1,5 +1,6 @@ // list-view.tsx 'use client'; +import type { ICard } from '@dreampipcom/oneiros'; import type { INCharacter, IDPayload } from '@types'; import { useContext, useEffect, useRef, useMemo } from 'react'; @@ -13,7 +14,7 @@ import { CardGrid as DPCardGrid } from "@dreampipcom/oneiros"; // to-do: character type annotations interface VCharactersListProps { - characters: INCharacter[]; + characters: ICard[]; } type VRMListProps = VCharactersListProps; @@ -35,9 +36,9 @@ export const VRMList = ({ characters }: VRMListProps) => { const dispatchAddToFavorites = async (cid?: number) => { const func = async (payload: IDPayload) => { - await addToFavorites(); + await addToFavorites({ listings: [cid] }); const op_2 = await getChars(); - loadChars({ characters: op_2 }); + loadChars({ listings: op_2 }); }; favChar({ email, cid }, func); }; @@ -69,20 +70,12 @@ export const VRMList = ({ characters }: VRMListProps) => { }, []); const adaptedCharsToCards = useMemo(() => { - return chars?.map((char) => ({ - id: `list__char--${char?.name}`, - className: '', + const res = chars?.map((char) => ({ + ...char, onLike: () => {}, - title: `${char?.name}`, - where: `${char?.location?.name}`, - when: `${char?.status}`, - image: `${char?.image}`, - price: '299€', - link: 'https://www.dreampip.com', - badgeLink: 'https://www.dreampip.com', - rating: '3/5', - selected: false, })) + console.log({ chars, res }) + return res }, [chars]); if (!authd || !characters) return; diff --git a/src/app/components/client/elements/signup-view.tsx b/src/app/components/client/elements/signup-view.tsx index 7060a46d..5a6deaa0 100644 --- a/src/app/components/client/elements/signup-view.tsx +++ b/src/app/components/client/elements/signup-view.tsx @@ -61,6 +61,7 @@ export const VSignUp = ({ providers, user }: VSignUpProps) => { name: user?.name || user?.email, avatar: user?.image, email: user?.email, + user, }); initd.current = true; } diff --git a/src/app/components/server/blocks/hypnos-public-list.tsx b/src/app/components/server/blocks/hypnos-public-list.tsx index 1a47e02e..7c3e68b5 100644 --- a/src/app/components/server/blocks/hypnos-public-list.tsx +++ b/src/app/components/server/blocks/hypnos-public-list.tsx @@ -2,7 +2,7 @@ 'use server'; import type { ICard } from '@dreampipcom/oneiros'; import { VHPNPList } from '@elements/client'; -import { loadHypnosPublicListings } from '@gateway'; +import { loadHypnosPublicListings, addToFavorites } from '@gateway'; import { HypnosPublicProvider } from '@state'; export const CHPNPList = async () => { diff --git a/src/app/components/server/blocks/rm-list.tsx b/src/app/components/server/blocks/rm-list.tsx index 63308221..7665cf30 100644 --- a/src/app/components/server/blocks/rm-list.tsx +++ b/src/app/components/server/blocks/rm-list.tsx @@ -1,12 +1,12 @@ // list-controller.tsx 'use server'; -import type { INCharacter } from '@types'; +import type { ICard } from '@dreampipcom/oneiros'; import { VRMList } from '@elements/client'; import { loadChars } from '@gateway'; import { RickMortyProvider } from '@state'; export const CRMList = async () => { - const characters: INCharacter[] = await loadChars(); + const characters: ICard[] = await loadChars(); return ( diff --git a/src/app/components/server/blocks/topnav.tsx b/src/app/components/server/blocks/topnav.tsx index 87c8bbde..32a391c8 100644 --- a/src/app/components/server/blocks/topnav.tsx +++ b/src/app/components/server/blocks/topnav.tsx @@ -3,6 +3,7 @@ import type { UserSchema } from '@types'; import { getSession } from '@auth'; import { VTopNav } from '@blocks/client'; +import { cookies } from 'next/headers'; interface ITopNavProps { user?: UserSchema | undefined; @@ -21,7 +22,10 @@ interface IAuthProviders { } export const CTopNav = async ({ user }: ITopNavProps) => { - const session = await getSession(); + const cookieStore = cookies().getAll(); + const cookieStr = cookieStore.toString(); + + const session = await getSession({ cookies: cookieStr }); return
; diff --git a/src/app/gateway/index.ts b/src/app/gateway/index.ts index a159ea0c..bc437106 100644 --- a/src/app/gateway/index.ts +++ b/src/app/gateway/index.ts @@ -4,7 +4,10 @@ export { navigate } from './client/actions'; // server -export { getUser, addToFavorites, loadChars, reloadChars, getChars } from './server/actions'; +export { getUser, loadChars, reloadChars, getChars } from './server/actions'; -// smokey-public +// hypnos-public export { loadHypnosPublicListings } from './server/hypnos/public'; + +// hypnos-private +export { addToFavorites } from './server/hypnos/private'; diff --git a/src/app/gateway/server/actions.ts b/src/app/gateway/server/actions.ts index cbbcc723..df3d921f 100644 --- a/src/app/gateway/server/actions.ts +++ b/src/app/gateway/server/actions.ts @@ -2,16 +2,17 @@ // actions.ts 'use server'; // import type { UserSchema } from '@types'; +import { cookies } from 'next/headers'; import { getRMCharacters } from '@controller'; import { decorateRMCharacters } from '@model'; import { getSession } from '@auth'; /* to-do: move to RM directory */ export async function loadChars() { - const session = await getSession(); - const email = session?.user?.email || ''; + const session = await getSession({ cookies: cookies().toString() }); + const user = session?.user; const chars = (await getRMCharacters()).results; - const decd = await decorateRMCharacters(chars, email); + const decd = await decorateRMCharacters(chars, user); return decd; } diff --git a/src/app/gateway/server/hypnos/private/actions.ts b/src/app/gateway/server/hypnos/private/actions.ts new file mode 100644 index 00000000..72d21489 --- /dev/null +++ b/src/app/gateway/server/hypnos/private/actions.ts @@ -0,0 +1,24 @@ +/* eslint @typescript-eslint/consistent-type-assertions:0 */ +// hypnos/private/actions.ts +'use server'; +// import type { UserSchema } from '@types'; +import { updateUserFavoriteListings } from '@controller'; +export async function addToFavorites({ listings }: any) { + await updateUserFavoriteListings({ listings }); + + return { ok: true }; +} + +/* to-do: +understand server components pragma better +so i can split into multiple files */ + +export async function getUser() { + // const session = await getServerSession(finalAuth); + // const email = session?.user?.email || ''; + // const user = await getUserMeta(email); + + return { user: { email: 'lorem' } as any }; + // we might need to decorate users in the future, + // reference decorateRMCharactes() +} diff --git a/src/app/gateway/server/hypnos/private/index.ts b/src/app/gateway/server/hypnos/private/index.ts new file mode 100644 index 00000000..a76a45d8 --- /dev/null +++ b/src/app/gateway/server/hypnos/private/index.ts @@ -0,0 +1,2 @@ +// index.ts +export * from './actions'; diff --git a/src/app/gateway/server/hypnos/public/actions.ts b/src/app/gateway/server/hypnos/public/actions.ts index 8aa960f0..2cffcd77 100644 --- a/src/app/gateway/server/hypnos/public/actions.ts +++ b/src/app/gateway/server/hypnos/public/actions.ts @@ -2,15 +2,16 @@ // hypnos/public/actions.ts 'use server'; // import type { UserSchema } from '@types'; +import { cookies } from 'next/headers'; import { getHypnosPublicListings } from '@controller'; import { decorateHypnosPublicListings } from '@model'; import { getSession } from '@auth'; export async function loadHypnosPublicListings() { - const session = await getSession(); - const email = session?.user?.email || ''; + const session = await getSession({ cookies: cookies().toString() }); + const user = session?.user; const chars = await getHypnosPublicListings({}); - const decd = await decorateHypnosPublicListings(chars, email); + const decd = await decorateHypnosPublicListings(chars, user); return decd; } @@ -23,11 +24,6 @@ export async function reloadHypnosPublicListings() { return { ok: true }; } -export async function addToFavorites() { - // await _addToFavorites({ email, cid, type: 'characters' }); - return { ok: true }; -} - /* to-do: understand server components pragma better so i can split into multiple files */