Added currency selection and auto-convertion
This commit is contained in:
		
							parent
							
								
									250adfc746
								
							
						
					
					
						commit
						f5c661c623
					
				| @ -13,7 +13,8 @@ import ReactTooltip from "react-tooltip"; | |||||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | import { useAppLayout } from "contexts/AppLayoutContext"; | ||||||
| import { ImageQuality } from "./Img"; | import { ImageQuality } from "./Img"; | ||||||
| import Popup from "./Popup"; | import Popup from "./Popup"; | ||||||
| import { useEffect } from "react"; | import { useEffect, useState } from "react"; | ||||||
|  | import Select from "./Select"; | ||||||
| 
 | 
 | ||||||
| type AppLayoutProps = { | type AppLayoutProps = { | ||||||
|   subPanel?: React.ReactNode; |   subPanel?: React.ReactNode; | ||||||
| @ -96,7 +97,20 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | |||||||
|     document.getElementsByTagName("html")[0].style.fontSize = `${ |     document.getElementsByTagName("html")[0].style.fontSize = `${ | ||||||
|       (appLayout.fontSize || 1) * 100 |       (appLayout.fontSize || 1) * 100 | ||||||
|     }%`;
 |     }%`;
 | ||||||
|   }); |   }, [appLayout.fontSize]); | ||||||
|  | 
 | ||||||
|  |   const currencyOptions = ["EUR", "USD", "CAD", "JPY"]; | ||||||
|  |   const [currencySelect, setCurrencySelect] = useState<number>(-1); | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     appLayout.currency && | ||||||
|  |       setCurrencySelect(currencyOptions.indexOf(appLayout.currency)); | ||||||
|  |   }, [appLayout.currency]); | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     currencySelect >= 0 && | ||||||
|  |       appLayout.setCurrency(currencyOptions[currencySelect]); | ||||||
|  |   }, [currencySelect]); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div |     <div | ||||||
| @ -268,93 +282,115 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | |||||||
|         > |         > | ||||||
|           <h2 className="text-2xl">Settings</h2> |           <h2 className="text-2xl">Settings</h2> | ||||||
| 
 | 
 | ||||||
|           <h3 className="text-xl mt-4">Theme</h3> |           <div className="mt-4 grid gap-8 place-items-center text-center desktop:grid-cols-2"> | ||||||
|           <div className="flex flex-row"> |             <div> | ||||||
|             <Button |               <h3 className="text-xl">Theme</h3> | ||||||
|               onClick={() => { |               <div className="flex flex-row"> | ||||||
|                 appLayout.setDarkMode(false); |                 <Button | ||||||
|                 appLayout.setSelectedThemeMode(true); |                   onClick={() => { | ||||||
|               }} |                     appLayout.setDarkMode(false); | ||||||
|               active={ |                     appLayout.setSelectedThemeMode(true); | ||||||
|                 appLayout.selectedThemeMode === true && |                   }} | ||||||
|                 appLayout.darkMode === false |                   active={ | ||||||
|               } |                     appLayout.selectedThemeMode === true && | ||||||
|               className="rounded-r-none" |                     appLayout.darkMode === false | ||||||
|             > |                   } | ||||||
|               Light |                   className="rounded-r-none" | ||||||
|             </Button> |                 > | ||||||
|             <Button |                   Light | ||||||
|               onClick={() => { |                 </Button> | ||||||
|                 appLayout.setSelectedThemeMode(false); |                 <Button | ||||||
|               }} |                   onClick={() => { | ||||||
|               active={appLayout.selectedThemeMode === false} |                     appLayout.setSelectedThemeMode(false); | ||||||
|               className="rounded-l-none rounded-r-none border-x-0" |                   }} | ||||||
|             > |                   active={appLayout.selectedThemeMode === false} | ||||||
|               Auto |                   className="rounded-l-none rounded-r-none border-x-0" | ||||||
|             </Button> |                 > | ||||||
|             <Button |                   Auto | ||||||
|               onClick={() => { |                 </Button> | ||||||
|                 appLayout.setDarkMode(true); |                 <Button | ||||||
|                 appLayout.setSelectedThemeMode(true); |                   onClick={() => { | ||||||
|               }} |                     appLayout.setDarkMode(true); | ||||||
|               active={ |                     appLayout.setSelectedThemeMode(true); | ||||||
|                 appLayout.selectedThemeMode === true && |                   }} | ||||||
|                 appLayout.darkMode === true |                   active={ | ||||||
|               } |                     appLayout.selectedThemeMode === true && | ||||||
|               className="rounded-l-none" |                     appLayout.darkMode === true | ||||||
|             > |                   } | ||||||
|               Dark |                   className="rounded-l-none" | ||||||
|             </Button> |                 > | ||||||
|           </div> |                   Dark | ||||||
|  |                 </Button> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
| 
 | 
 | ||||||
|           <h3 className="text-xl mt-4">Font size</h3> |             <div> | ||||||
|           <div className="flex flex-row"> |               <h3 className="text-xl">Currency</h3> | ||||||
|             <Button |               <div> | ||||||
|               className="rounded-r-none" |                 <Select | ||||||
|               onClick={() => |                   options={currencyOptions} | ||||||
|                 appLayout.setFontSize( |                   state={currencySelect} | ||||||
|                   appLayout.fontSize ? appLayout.fontSize / 1.05 : 1 / 1.05 |                   setState={setCurrencySelect} | ||||||
|                 ) |                   className="w-28" | ||||||
|               } |                 /> | ||||||
|             > |               </div> | ||||||
|               <span className="material-icons">text_decrease</span> |             </div> | ||||||
|             </Button> |  | ||||||
|             <Button |  | ||||||
|               className="rounded-l-none rounded-r-none border-x-0" |  | ||||||
|               onClick={() => appLayout.setFontSize(1)} |  | ||||||
|             > |  | ||||||
|               {((appLayout.fontSize || 1) * 100).toLocaleString(undefined, { |  | ||||||
|                 maximumFractionDigits: 0, |  | ||||||
|               })} |  | ||||||
|               % |  | ||||||
|             </Button> |  | ||||||
|             <Button |  | ||||||
|               className="rounded-l-none" |  | ||||||
|               onClick={() => |  | ||||||
|                 appLayout.setFontSize( |  | ||||||
|                   appLayout.fontSize ? appLayout.fontSize * 1.05 : 1 * 1.05 |  | ||||||
|                 ) |  | ||||||
|               } |  | ||||||
|             > |  | ||||||
|               <span className="material-icons">text_increase</span> |  | ||||||
|             </Button> |  | ||||||
|           </div> |  | ||||||
| 
 | 
 | ||||||
|           <h3 className="text-xl mt-4">Font</h3> |             <div> | ||||||
|           <Button |               <h3 className="text-xl">Font size</h3> | ||||||
|             active={appLayout.dyslexic === false} |               <div className="flex flex-row"> | ||||||
|             onClick={() => appLayout.setDyslexic(false)} |                 <Button | ||||||
|             className="font-zenMaruGothic" |                   className="rounded-r-none" | ||||||
|           > |                   onClick={() => | ||||||
|             Zen Maru Gothic |                     appLayout.setFontSize( | ||||||
|           </Button> |                       appLayout.fontSize ? appLayout.fontSize / 1.05 : 1 / 1.05 | ||||||
|           <Button |                     ) | ||||||
|             active={appLayout.dyslexic === true} |                   } | ||||||
|             onClick={() => appLayout.setDyslexic(true)} |                 > | ||||||
|             className="font-openDyslexic" |                   <span className="material-icons">text_decrease</span> | ||||||
|           > |                 </Button> | ||||||
|             OpenDyslexic |                 <Button | ||||||
|           </Button> |                   className="rounded-l-none rounded-r-none border-x-0" | ||||||
|  |                   onClick={() => appLayout.setFontSize(1)} | ||||||
|  |                 > | ||||||
|  |                   {((appLayout.fontSize || 1) * 100).toLocaleString(undefined, { | ||||||
|  |                     maximumFractionDigits: 0, | ||||||
|  |                   })} | ||||||
|  |                   % | ||||||
|  |                 </Button> | ||||||
|  |                 <Button | ||||||
|  |                   className="rounded-l-none" | ||||||
|  |                   onClick={() => | ||||||
|  |                     appLayout.setFontSize( | ||||||
|  |                       appLayout.fontSize ? appLayout.fontSize * 1.05 : 1 * 1.05 | ||||||
|  |                     ) | ||||||
|  |                   } | ||||||
|  |                 > | ||||||
|  |                   <span className="material-icons">text_increase</span> | ||||||
|  |                 </Button> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div> | ||||||
|  |               <h3 className="text-xl">Font</h3> | ||||||
|  |               <div className="grid gap-2"> | ||||||
|  |                 <Button | ||||||
|  |                   active={appLayout.dyslexic === false} | ||||||
|  |                   onClick={() => appLayout.setDyslexic(false)} | ||||||
|  |                   className="font-zenMaruGothic" | ||||||
|  |                 > | ||||||
|  |                   Zen Maru Gothic | ||||||
|  |                 </Button> | ||||||
|  |                 <Button | ||||||
|  |                   active={appLayout.dyslexic === true} | ||||||
|  |                   onClick={() => appLayout.setDyslexic(true)} | ||||||
|  |                   className="font-openDyslexic" | ||||||
|  |                 > | ||||||
|  |                   OpenDyslexic | ||||||
|  |                 </Button> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|         </Popup> |         </Popup> | ||||||
| 
 | 
 | ||||||
|         <ReactTooltip |         <ReactTooltip | ||||||
|  | |||||||
| @ -1,8 +1,12 @@ | |||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import { GetLibraryItemsPreviewQuery } from "graphql/operations-types"; | import { | ||||||
|  |   GetCurrenciesQuery, | ||||||
|  |   GetLibraryItemsPreviewQuery, | ||||||
|  | } from "graphql/operations-types"; | ||||||
| import { prettyDate, prettyPrice, prettyItemSubType } from "queries/helpers"; | import { prettyDate, prettyPrice, prettyItemSubType } from "queries/helpers"; | ||||||
| import Chip from "components/Chip"; | import Chip from "components/Chip"; | ||||||
| import Img, { ImageQuality } from "components/Img"; | import Img, { ImageQuality } from "components/Img"; | ||||||
|  | import { useAppLayout } from "contexts/AppLayoutContext"; | ||||||
| 
 | 
 | ||||||
| export type LibraryItemsPreviewProps = { | export type LibraryItemsPreviewProps = { | ||||||
|   className?: string; |   className?: string; | ||||||
| @ -15,12 +19,14 @@ export type LibraryItemsPreviewProps = { | |||||||
|     release_date?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"]; |     release_date?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"]; | ||||||
|     metadata?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"]; |     metadata?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"]; | ||||||
|   }; |   }; | ||||||
|  |   currencies?: GetCurrenciesQuery["currencies"]["data"]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default function LibraryItemsPreview( | export default function LibraryItemsPreview( | ||||||
|   props: LibraryItemsPreviewProps |   props: LibraryItemsPreviewProps | ||||||
| ): JSX.Element { | ): JSX.Element { | ||||||
|   const item = props.item; |   const item = props.item; | ||||||
|  |   const appLayout = useAppLayout(); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Link href={"/library/" + item.slug} passHref> |     <Link href={"/library/" + item.slug} passHref> | ||||||
| @ -61,12 +67,16 @@ export default function LibraryItemsPreview( | |||||||
|               ) : ( |               ) : ( | ||||||
|                 "" |                 "" | ||||||
|               )} |               )} | ||||||
|               {item.price ? ( |               {item.price && props.currencies ? ( | ||||||
|                 <p className="mobile:text-xs text-sm justify-self-end"> |                 <p className="mobile:text-xs text-sm justify-self-end"> | ||||||
|                   <span className="material-icons !text-base translate-y-[.15em] mr-1"> |                   <span className="material-icons !text-base translate-y-[.15em] mr-1"> | ||||||
|                     shopping_cart |                     shopping_cart | ||||||
|                   </span> |                   </span> | ||||||
|                   {prettyPrice(item.price)} |                   {prettyPrice( | ||||||
|  |                     item.price, | ||||||
|  |                     props.currencies, | ||||||
|  |                     appLayout.currency | ||||||
|  |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               ) : ( |               ) : ( | ||||||
|                 "" |                 "" | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ export default function Select(props: SelectProps): JSX.Element { | |||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div |     <div | ||||||
|       className={`relative transition-[filter] ${ |       className={`relative text-center transition-[filter] ${ | ||||||
|         opened && "drop-shadow-shade-lg z-10" |         opened && "drop-shadow-shade-lg z-10" | ||||||
|       } ${props.className}`}
 |       } ${props.className}`}
 | ||||||
|     > |     > | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ export interface AppLayoutState { | |||||||
|   selectedThemeMode: boolean | undefined; |   selectedThemeMode: boolean | undefined; | ||||||
|   fontSize: number | undefined; |   fontSize: number | undefined; | ||||||
|   dyslexic: boolean | undefined; |   dyslexic: boolean | undefined; | ||||||
|  |   currency: string | undefined; | ||||||
|   setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>; |   setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>; | ||||||
|   setLanguagePanelOpen: React.Dispatch< |   setLanguagePanelOpen: React.Dispatch< | ||||||
|     React.SetStateAction<boolean | undefined> |     React.SetStateAction<boolean | undefined> | ||||||
| @ -27,6 +28,7 @@ export interface AppLayoutState { | |||||||
|   >; |   >; | ||||||
|   setFontSize: React.Dispatch<React.SetStateAction<number | undefined>>; |   setFontSize: React.Dispatch<React.SetStateAction<number | undefined>>; | ||||||
|   setDyslexic: React.Dispatch<React.SetStateAction<boolean | undefined>>; |   setDyslexic: React.Dispatch<React.SetStateAction<boolean | undefined>>; | ||||||
|  |   setCurrency: React.Dispatch<React.SetStateAction<string | undefined>>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const initialState: AppLayoutState = { | const initialState: AppLayoutState = { | ||||||
| @ -39,6 +41,7 @@ const initialState: AppLayoutState = { | |||||||
|   selectedThemeMode: false, |   selectedThemeMode: false, | ||||||
|   fontSize: 1, |   fontSize: 1, | ||||||
|   dyslexic: false, |   dyslexic: false, | ||||||
|  |   currency: "USD", | ||||||
|   setSubPanelOpen: () => {}, |   setSubPanelOpen: () => {}, | ||||||
|   setLanguagePanelOpen: () => {}, |   setLanguagePanelOpen: () => {}, | ||||||
|   setMainPanelReduced: () => {}, |   setMainPanelReduced: () => {}, | ||||||
| @ -48,6 +51,7 @@ const initialState: AppLayoutState = { | |||||||
|   setConfigPanelOpen: () => {}, |   setConfigPanelOpen: () => {}, | ||||||
|   setFontSize: () => {}, |   setFontSize: () => {}, | ||||||
|   setDyslexic: () => {}, |   setDyslexic: () => {}, | ||||||
|  |   setCurrency: () => {}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const AppContext = React.createContext<AppLayoutState>(initialState); | const AppContext = React.createContext<AppLayoutState>(initialState); | ||||||
| @ -96,6 +100,11 @@ export const AppContextProvider = (props: Props) => { | |||||||
|     initialState.dyslexic |     initialState.dyslexic | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|  |   const [currency, setCurrency] = useStateWithLocalStorage<string | undefined>( | ||||||
|  |     "currency", | ||||||
|  |     initialState.currency | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <AppContext.Provider |     <AppContext.Provider | ||||||
|       value={{ |       value={{ | ||||||
| @ -108,6 +117,7 @@ export const AppContextProvider = (props: Props) => { | |||||||
|         selectedThemeMode, |         selectedThemeMode, | ||||||
|         fontSize, |         fontSize, | ||||||
|         dyslexic, |         dyslexic, | ||||||
|  |         currency, | ||||||
|         setSubPanelOpen, |         setSubPanelOpen, | ||||||
|         setLanguagePanelOpen, |         setLanguagePanelOpen, | ||||||
|         setConfigPanelOpen, |         setConfigPanelOpen, | ||||||
| @ -117,6 +127,7 @@ export const AppContextProvider = (props: Props) => { | |||||||
|         setSelectedThemeMode, |         setSelectedThemeMode, | ||||||
|         setFontSize, |         setFontSize, | ||||||
|         setDyslexic, |         setDyslexic, | ||||||
|  |         setCurrency, | ||||||
|       }} |       }} | ||||||
|     > |     > | ||||||
|       {props.children} |       {props.children} | ||||||
|  | |||||||
| @ -174,6 +174,7 @@ query getLibraryItemsPreview($language_code: String) { | |||||||
|               attributes { |               attributes { | ||||||
|                 symbol |                 symbol | ||||||
|                 code |                 code | ||||||
|  |                 rate_to_usd | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
| @ -322,6 +323,7 @@ query getLibraryItem($slug: String, $language_code: String) { | |||||||
|               attributes { |               attributes { | ||||||
|                 symbol |                 symbol | ||||||
|                 code |                 code | ||||||
|  |                 rate_to_usd | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
| @ -490,6 +492,7 @@ query getLibraryItem($slug: String, $language_code: String) { | |||||||
|                     attributes { |                     attributes { | ||||||
|                       symbol |                       symbol | ||||||
|                       code |                       code | ||||||
|  |                       rate_to_usd | ||||||
|                     } |                     } | ||||||
|                   } |                   } | ||||||
|                 } |                 } | ||||||
| @ -1057,3 +1060,17 @@ query getContentText($slug: String, $language_code: String) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | query getCurrencies { | ||||||
|  |   currencies { | ||||||
|  |     data { | ||||||
|  |       id | ||||||
|  |       attributes { | ||||||
|  |         code | ||||||
|  |         symbol | ||||||
|  |         rate_to_usd | ||||||
|  |         display_decimals | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
| @ -286,6 +286,7 @@ export type GetLibraryItemsPreviewQuery = { | |||||||
|                 __typename: "Currency"; |                 __typename: "Currency"; | ||||||
|                 symbol: string; |                 symbol: string; | ||||||
|                 code: string; |                 code: string; | ||||||
|  |                 rate_to_usd: number; | ||||||
|               }; |               }; | ||||||
|             }; |             }; | ||||||
|           }; |           }; | ||||||
| @ -478,6 +479,7 @@ export type GetLibraryItemQuery = { | |||||||
|                 __typename: "Currency"; |                 __typename: "Currency"; | ||||||
|                 symbol: string; |                 symbol: string; | ||||||
|                 code: string; |                 code: string; | ||||||
|  |                 rate_to_usd: number; | ||||||
|               }; |               }; | ||||||
|             }; |             }; | ||||||
|           }; |           }; | ||||||
| @ -693,6 +695,7 @@ export type GetLibraryItemQuery = { | |||||||
|                       __typename: "Currency"; |                       __typename: "Currency"; | ||||||
|                       symbol: string; |                       symbol: string; | ||||||
|                       code: string; |                       code: string; | ||||||
|  |                       rate_to_usd: number; | ||||||
|                     }; |                     }; | ||||||
|                   }; |                   }; | ||||||
|                 }; |                 }; | ||||||
| @ -1416,3 +1419,23 @@ export type GetContentTextQuery = { | |||||||
|     }>; |     }>; | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export type GetCurrenciesQueryVariables = Exact<{ [key: string]: never }>; | ||||||
|  | 
 | ||||||
|  | export type GetCurrenciesQuery = { | ||||||
|  |   __typename: "Query"; | ||||||
|  |   currencies: { | ||||||
|  |     __typename: "CurrencyEntityResponseCollection"; | ||||||
|  |     data: Array<{ | ||||||
|  |       __typename: "CurrencyEntity"; | ||||||
|  |       id: string; | ||||||
|  |       attributes: { | ||||||
|  |         __typename: "Currency"; | ||||||
|  |         code: string; | ||||||
|  |         symbol: string; | ||||||
|  |         rate_to_usd: number; | ||||||
|  |         display_decimals: boolean; | ||||||
|  |       }; | ||||||
|  |     }>; | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ import { | |||||||
|   GetContentsSlugsQueryVariables, |   GetContentsSlugsQueryVariables, | ||||||
|   GetContentTextQuery, |   GetContentTextQuery, | ||||||
|   GetContentTextQueryVariables, |   GetContentTextQueryVariables, | ||||||
|  |   GetCurrenciesQuery, | ||||||
|  |   GetCurrenciesQueryVariables, | ||||||
|   GetErasQuery, |   GetErasQuery, | ||||||
|   GetErasQueryVariables, |   GetErasQueryVariables, | ||||||
|   GetLibraryItemQuery, |   GetLibraryItemQuery, | ||||||
| @ -123,3 +125,10 @@ export async function getContentText( | |||||||
|   const query = getQueryFromOperations("getContentText"); |   const query = getQueryFromOperations("getContentText"); | ||||||
|   return await graphQL(query, JSON.stringify(variables)); |   return await graphQL(query, JSON.stringify(variables)); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export async function getCurrencies( | ||||||
|  |   variables: GetCurrenciesQueryVariables | ||||||
|  | ): Promise<GetCurrenciesQuery> { | ||||||
|  |   const query = getQueryFromOperations("getCurrencies"); | ||||||
|  |   return await graphQL(query, JSON.stringify(variables)); | ||||||
|  | } | ||||||
|  | |||||||
| @ -1647,6 +1647,7 @@ input CurrencyFiltersInput { | |||||||
|   id: IDFilterInput |   id: IDFilterInput | ||||||
|   symbol: StringFilterInput |   symbol: StringFilterInput | ||||||
|   code: StringFilterInput |   code: StringFilterInput | ||||||
|  |   rate_to_usd: FloatFilterInput | ||||||
|   createdAt: DateTimeFilterInput |   createdAt: DateTimeFilterInput | ||||||
|   updatedAt: DateTimeFilterInput |   updatedAt: DateTimeFilterInput | ||||||
|   and: [CurrencyFiltersInput] |   and: [CurrencyFiltersInput] | ||||||
| @ -1657,11 +1658,13 @@ input CurrencyFiltersInput { | |||||||
| input CurrencyInput { | input CurrencyInput { | ||||||
|   symbol: String |   symbol: String | ||||||
|   code: String |   code: String | ||||||
|  |   rate_to_usd: Float | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Currency { | type Currency { | ||||||
|   symbol: String! |   symbol: String! | ||||||
|   code: String! |   code: String! | ||||||
|  |   rate_to_usd: Float | ||||||
|   createdAt: DateTime |   createdAt: DateTime | ||||||
|   updatedAt: DateTime |   updatedAt: DateTime | ||||||
| } | } | ||||||
| @ -2099,46 +2102,6 @@ type MetadataTypeEntityResponseCollection { | |||||||
|   meta: ResponseCollectionMeta! |   meta: ResponseCollectionMeta! | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| input OtherSubtypeFiltersInput { |  | ||||||
|   id: IDFilterInput |  | ||||||
|   slug: StringFilterInput |  | ||||||
|   createdAt: DateTimeFilterInput |  | ||||||
|   updatedAt: DateTimeFilterInput |  | ||||||
|   and: [OtherSubtypeFiltersInput] |  | ||||||
|   or: [OtherSubtypeFiltersInput] |  | ||||||
|   not: OtherSubtypeFiltersInput |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| input OtherSubtypeInput { |  | ||||||
|   slug: String |  | ||||||
|   titles: [ComponentTranslationsSimpleTitleInput] |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type OtherSubtype { |  | ||||||
|   slug: String! |  | ||||||
|   titles( |  | ||||||
|     filters: ComponentTranslationsSimpleTitleFiltersInput |  | ||||||
|     pagination: PaginationArg = {} |  | ||||||
|     sort: [String] = [] |  | ||||||
|   ): [ComponentTranslationsSimpleTitle] |  | ||||||
|   createdAt: DateTime |  | ||||||
|   updatedAt: DateTime |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type OtherSubtypeEntity { |  | ||||||
|   id: ID |  | ||||||
|   attributes: OtherSubtype |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type OtherSubtypeEntityResponse { |  | ||||||
|   data: OtherSubtypeEntity |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type OtherSubtypeEntityResponseCollection { |  | ||||||
|   data: [OtherSubtypeEntity!]! |  | ||||||
|   meta: ResponseCollectionMeta! |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| input PostFiltersInput { | input PostFiltersInput { | ||||||
|   id: IDFilterInput |   id: IDFilterInput | ||||||
|   authors: RecorderFiltersInput |   authors: RecorderFiltersInput | ||||||
| @ -2655,6 +2618,7 @@ input WebsiteInterfaceFiltersInput { | |||||||
|   order_by: StringFilterInput |   order_by: StringFilterInput | ||||||
|   group_by: StringFilterInput |   group_by: StringFilterInput | ||||||
|   select_option_sidebar: StringFilterInput |   select_option_sidebar: StringFilterInput | ||||||
|  |   group: StringFilterInput | ||||||
|   createdAt: DateTimeFilterInput |   createdAt: DateTimeFilterInput | ||||||
|   updatedAt: DateTimeFilterInput |   updatedAt: DateTimeFilterInput | ||||||
|   and: [WebsiteInterfaceFiltersInput] |   and: [WebsiteInterfaceFiltersInput] | ||||||
| @ -2742,6 +2706,7 @@ input WebsiteInterfaceInput { | |||||||
|   order_by: String |   order_by: String | ||||||
|   group_by: String |   group_by: String | ||||||
|   select_option_sidebar: String |   select_option_sidebar: String | ||||||
|  |   group: String | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type WebsiteInterface { | type WebsiteInterface { | ||||||
| @ -2824,6 +2789,7 @@ type WebsiteInterface { | |||||||
|   order_by: String |   order_by: String | ||||||
|   group_by: String |   group_by: String | ||||||
|   select_option_sidebar: String |   select_option_sidebar: String | ||||||
|  |   group: String | ||||||
|   createdAt: DateTime |   createdAt: DateTime | ||||||
|   updatedAt: DateTime |   updatedAt: DateTime | ||||||
| } | } | ||||||
| @ -2997,7 +2963,6 @@ union GenericMorph = | |||||||
|   | LibraryItem |   | LibraryItem | ||||||
|   | MerchItem |   | MerchItem | ||||||
|   | MetadataType |   | MetadataType | ||||||
|   | OtherSubtype |  | ||||||
|   | Post |   | Post | ||||||
|   | RangedContent |   | RangedContent | ||||||
|   | Recorder |   | Recorder | ||||||
| @ -3121,12 +3086,6 @@ type Query { | |||||||
|     pagination: PaginationArg = {} |     pagination: PaginationArg = {} | ||||||
|     sort: [String] = [] |     sort: [String] = [] | ||||||
|   ): MetadataTypeEntityResponseCollection |   ): MetadataTypeEntityResponseCollection | ||||||
|   otherSubtype(id: ID): OtherSubtypeEntityResponse |  | ||||||
|   otherSubtypes( |  | ||||||
|     filters: OtherSubtypeFiltersInput |  | ||||||
|     pagination: PaginationArg = {} |  | ||||||
|     sort: [String] = [] |  | ||||||
|   ): OtherSubtypeEntityResponseCollection |  | ||||||
|   post(id: ID): PostEntityResponse |   post(id: ID): PostEntityResponse | ||||||
|   posts( |   posts( | ||||||
|     filters: PostFiltersInput |     filters: PostFiltersInput | ||||||
| @ -3277,12 +3236,6 @@ type Mutation { | |||||||
|     data: MetadataTypeInput! |     data: MetadataTypeInput! | ||||||
|   ): MetadataTypeEntityResponse |   ): MetadataTypeEntityResponse | ||||||
|   deleteMetadataType(id: ID!): MetadataTypeEntityResponse |   deleteMetadataType(id: ID!): MetadataTypeEntityResponse | ||||||
|   createOtherSubtype(data: OtherSubtypeInput!): OtherSubtypeEntityResponse |  | ||||||
|   updateOtherSubtype( |  | ||||||
|     id: ID! |  | ||||||
|     data: OtherSubtypeInput! |  | ||||||
|   ): OtherSubtypeEntityResponse |  | ||||||
|   deleteOtherSubtype(id: ID!): OtherSubtypeEntityResponse |  | ||||||
|   createPost(data: PostInput!): PostEntityResponse |   createPost(data: PostInput!): PostEntityResponse | ||||||
|   updatePost(id: ID!, data: PostInput!): PostEntityResponse |   updatePost(id: ID!, data: PostInput!): PostEntityResponse | ||||||
|   deletePost(id: ID!): PostEntityResponse |   deletePost(id: ID!): PostEntityResponse | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import ContentPanel, { | |||||||
| } from "components/Panels/ContentPanel"; | } from "components/Panels/ContentPanel"; | ||||||
| import { GetStaticPaths, GetStaticProps } from "next"; | import { GetStaticPaths, GetStaticProps } from "next"; | ||||||
| import { | import { | ||||||
|  |   getCurrencies, | ||||||
|   getLibraryItem, |   getLibraryItem, | ||||||
|   getLibraryItemsSlugs, |   getLibraryItemsSlugs, | ||||||
|   getWebsiteInterface, |   getWebsiteInterface, | ||||||
| @ -10,6 +11,7 @@ import { | |||||||
| import { | import { | ||||||
|   Enum_Componentmetadatabooks_Binding_Type, |   Enum_Componentmetadatabooks_Binding_Type, | ||||||
|   Enum_Componentmetadatabooks_Page_Order, |   Enum_Componentmetadatabooks_Page_Order, | ||||||
|  |   GetCurrenciesQuery, | ||||||
|   GetLibraryItemQuery, |   GetLibraryItemQuery, | ||||||
|   GetWebsiteInterfaceQuery, |   GetWebsiteInterfaceQuery, | ||||||
| } from "graphql/operations-types"; | } from "graphql/operations-types"; | ||||||
| @ -20,7 +22,6 @@ import { | |||||||
|   prettyItemType, |   prettyItemType, | ||||||
|   prettyItemSubType, |   prettyItemSubType, | ||||||
|   prettyPrice, |   prettyPrice, | ||||||
|   prettySlug, |  | ||||||
|   prettyTestError, |   prettyTestError, | ||||||
|   prettyTestWarning, |   prettyTestWarning, | ||||||
|   sortContent, |   sortContent, | ||||||
| @ -32,7 +33,6 @@ import ReturnButton, { | |||||||
| import NavOption from "components/PanelComponents/NavOption"; | import NavOption from "components/PanelComponents/NavOption"; | ||||||
| import Chip from "components/Chip"; | import Chip from "components/Chip"; | ||||||
| import Button from "components/Button"; | import Button from "components/Button"; | ||||||
| import HorizontalLine from "components/HorizontalLine"; |  | ||||||
| import AppLayout from "components/AppLayout"; | import AppLayout from "components/AppLayout"; | ||||||
| import LibraryItemsPreview from "components/Library/LibraryItemsPreview"; | import LibraryItemsPreview from "components/Library/LibraryItemsPreview"; | ||||||
| import InsetBox from "components/InsetBox"; | import InsetBox from "components/InsetBox"; | ||||||
| @ -44,12 +44,14 @@ import ContentTOCLine from "components/Library/ContentTOCLine"; | |||||||
| interface LibrarySlugProps { | interface LibrarySlugProps { | ||||||
|   libraryItem: GetLibraryItemQuery; |   libraryItem: GetLibraryItemQuery; | ||||||
|   langui: GetWebsiteInterfaceQuery; |   langui: GetWebsiteInterfaceQuery; | ||||||
|  |   currencies: GetCurrenciesQuery; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||||
|   useTesting(props); |   useTesting(props); | ||||||
|   const item = props.libraryItem.libraryItems.data[0].attributes; |   const item = props.libraryItem.libraryItems.data[0].attributes; | ||||||
|   const langui = props.langui.websiteInterfaces.data[0].attributes; |   const langui = props.langui.websiteInterfaces.data[0].attributes; | ||||||
|  |   const currencies = props.currencies.currencies.data; | ||||||
|   const appLayout = useAppLayout(); |   const appLayout = useAppLayout(); | ||||||
| 
 | 
 | ||||||
|   const isVariantSet = |   const isVariantSet = | ||||||
| @ -226,7 +228,9 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | |||||||
|               {item.price ? ( |               {item.price ? ( | ||||||
|                 <div className="grid place-items-center"> |                 <div className="grid place-items-center"> | ||||||
|                   <h3 className="text-xl">{langui.price}</h3> |                   <h3 className="text-xl">{langui.price}</h3> | ||||||
|                   <p>{prettyPrice(item.price)}</p> |                   <p> | ||||||
|  |                     {prettyPrice(item.price, currencies, appLayout.currency)} | ||||||
|  |                   </p> | ||||||
|                 </div> |                 </div> | ||||||
|               ) : ( |               ) : ( | ||||||
|                 "" |                 "" | ||||||
| @ -409,6 +413,7 @@ export const getStaticProps: GetStaticProps = async (context) => { | |||||||
|         langui: await getWebsiteInterface({ |         langui: await getWebsiteInterface({ | ||||||
|           language_code: context.locale, |           language_code: context.locale, | ||||||
|         }), |         }), | ||||||
|  |         currencies: await getCurrencies({}), | ||||||
|       }; |       }; | ||||||
|       return { |       return { | ||||||
|         props: props, |         props: props, | ||||||
|  | |||||||
| @ -4,10 +4,12 @@ import ContentPanel, { | |||||||
|   ContentPanelWidthSizes, |   ContentPanelWidthSizes, | ||||||
| } from "components/Panels/ContentPanel"; | } from "components/Panels/ContentPanel"; | ||||||
| import { | import { | ||||||
|  |   GetCurrenciesQuery, | ||||||
|   GetLibraryItemsPreviewQuery, |   GetLibraryItemsPreviewQuery, | ||||||
|   GetWebsiteInterfaceQuery, |   GetWebsiteInterfaceQuery, | ||||||
| } from "graphql/operations-types"; | } from "graphql/operations-types"; | ||||||
| import { | import { | ||||||
|  |   getCurrencies, | ||||||
|   getLibraryItemsPreview, |   getLibraryItemsPreview, | ||||||
|   getWebsiteInterface, |   getWebsiteInterface, | ||||||
| } from "graphql/operations"; | } from "graphql/operations"; | ||||||
| @ -22,6 +24,7 @@ import Switch from "components/Switch"; | |||||||
| type LibraryProps = { | type LibraryProps = { | ||||||
|   libraryItems: GetLibraryItemsPreviewQuery; |   libraryItems: GetLibraryItemsPreviewQuery; | ||||||
|   langui: GetWebsiteInterfaceQuery; |   langui: GetWebsiteInterfaceQuery; | ||||||
|  |   currencies: GetCurrenciesQuery; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| type GroupLibraryItems = Map< | type GroupLibraryItems = Map< | ||||||
| @ -138,7 +141,11 @@ export default function Library(props: LibraryProps): JSX.Element { | |||||||
|                 className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0" |                 className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0" | ||||||
|               > |               > | ||||||
|                 {items.map((item) => ( |                 {items.map((item) => ( | ||||||
|                   <LibraryItemsPreview key={item.id} item={item.attributes} /> |                   <LibraryItemsPreview | ||||||
|  |                     key={item.id} | ||||||
|  |                     item={item.attributes} | ||||||
|  |                     currencies={props.currencies.currencies.data} | ||||||
|  |                   /> | ||||||
|                 ))} |                 ))} | ||||||
|               </div> |               </div> | ||||||
|             </> |             </> | ||||||
| @ -166,6 +173,7 @@ export const getStaticProps: GetStaticProps = async (context) => { | |||||||
|       langui: await getWebsiteInterface({ |       langui: await getWebsiteInterface({ | ||||||
|         language_code: context.locale, |         language_code: context.locale, | ||||||
|       }), |       }), | ||||||
|  |       currencies: await getCurrencies({}), | ||||||
|     }; |     }; | ||||||
|     return { |     return { | ||||||
|       props: props, |       props: props, | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import { | |||||||
|   ImageQuality, |   ImageQuality, | ||||||
| } from "components/Img"; | } from "components/Img"; | ||||||
| import { | import { | ||||||
|  |   GetCurrenciesQuery, | ||||||
|   GetLibraryItemQuery, |   GetLibraryItemQuery, | ||||||
|   GetLibraryItemsPreviewQuery, |   GetLibraryItemsPreviewQuery, | ||||||
|   GetWebsiteInterfaceQuery, |   GetWebsiteInterfaceQuery, | ||||||
| @ -24,12 +25,27 @@ export function prettyDate( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function prettyPrice( | export function prettyPrice( | ||||||
|   pricePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"] |   pricePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"], | ||||||
|  |   currencies: GetCurrenciesQuery["currencies"]["data"], | ||||||
|  |   targetCurrencyCode?: string | ||||||
| ): string { | ): string { | ||||||
|   return ( |   if (!targetCurrencyCode) return ""; | ||||||
|     pricePicker.currency.data.attributes.symbol + |   let result = ""; | ||||||
|     pricePicker.amount.toLocaleString() |   currencies.map((currency) => { | ||||||
|   ); |     if (currency.attributes.code === targetCurrencyCode) { | ||||||
|  |       let amountInUSD = | ||||||
|  |         pricePicker.amount * pricePicker.currency.data.attributes.rate_to_usd; | ||||||
|  |       let amountInTargetCurrency = | ||||||
|  |         amountInUSD / currency.attributes.rate_to_usd; | ||||||
|  |       result = | ||||||
|  |         currency.attributes.symbol + | ||||||
|  |         amountInTargetCurrency.toLocaleString(undefined, { | ||||||
|  |           minimumFractionDigits: currency.attributes.display_decimals ? 2 : 0, | ||||||
|  |           maximumFractionDigits: currency.attributes.display_decimals ? 2 : 0, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |   return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function prettySlug(slug?: string, parentSlug?: string): string { | export function prettySlug(slug?: string, parentSlug?: string): string { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint