Skip to content

Commit

Permalink
Merge pull request #68 from Blazity/mock-api
Browse files Browse the repository at this point in the history
feat: add market stock
  • Loading branch information
Pierniki authored Oct 17, 2023
2 parents afc5a0a + e7c4831 commit a5ccadb
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 46 deletions.
8 changes: 5 additions & 3 deletions src/app/[lang]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export default async function Web({ params }: { params: { lang: Locale } }) {

return (
<>
<div className="flex w-full justify-end">
<StockDisplay quotes={homepage.stockDailyQuotes} />
</div>
{homepage.marketStock?.data && (
<div className="flex w-full justify-end">
<StockDisplay quotes={homepage.marketStock?.data} />
</div>
)}

<TrendingArticles locale={params.lang} title={homepage.trendingSectionTitle ?? "Trending articles"} />
{homepage.highlightedArticles && (
Expand Down
4 changes: 2 additions & 2 deletions src/components/LangSelect/LangSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ function LangSelect() {

return (
<Select value={lang} onValueChange={(locale) => router.push(`/${locale}`)}>
<SelectTrigger className="w-[100px] min-w-[100px]" aria-label="language select">
<SelectValue>{lang}</SelectValue>
<SelectTrigger className="w-full min-w-full rounded-xl lg:w-[70px] lg:min-w-[70px]" aria-label="language select">
<SelectValue>{lang.toUpperCase()}</SelectValue>
</SelectTrigger>
<SelectContent className="bg-white">
<SelectGroup>
Expand Down
9 changes: 8 additions & 1 deletion src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Link from "next/link"
import { useState } from "react"
import { Locale } from "@/i18n/i18n"
import { getNavigation } from "@/lib/client"
import { DynamicLangSelect } from "../LangSelect/DynamicLangSelect"
import { DynamicSearchDialog } from "../Search/DynamicSearchDialog"
import { Button } from "../ui/Button/Button"
import { Sheet, SheetContent, SheetTrigger } from "../ui/Sheet/Sheet"
Expand Down Expand Up @@ -46,6 +47,9 @@ export function Navigation({ locale, navigation }: NavigationProps) {
<DynamicSearchDialog />
</li>
{navElements}
<li>
<DynamicLangSelect />
</li>
</ul>
<ul className="flex items-center sm:flex-wrap lg:hidden">
<li className="flex items-center">
Expand All @@ -59,8 +63,11 @@ export function Navigation({ locale, navigation }: NavigationProps) {
</Button>
</li>
</SheetTrigger>
<SheetContent className="mt-20 flex min-w-[100vw] list-none flex-col items-center justify-start text-center text-xl font-semibold">
<SheetContent className="mt-20 flex min-w-[100vw] list-none flex-col items-center justify-start text-center text-2xl font-semibold">
{navElements}
<li className="mt-20 w-full text-xl font-normal">
<DynamicLangSelect />
</li>
</SheetContent>
</Sheet>
</ul>
Expand Down
41 changes: 12 additions & 29 deletions src/components/StockDisplay/StockDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
import { z } from "zod"
import { StockDisplayRenderer } from "./StockDisplayRenderer"

type StockQuoteBase = {
id: string
name: string
}
type ValidStockQuote = StockQuoteBase & { quote: AlphaVantageQuote }

type AlphaVantageQuote = {
"Global Quote": {
"10. change percent": number
}
}

export async function StockDisplay({ quotes }: { quotes: { id: string; name: string; quote?: unknown }[] }) {
const validStockQuotes = quotes
.map((stockQuote) => ({
...stockQuote,
quote: validateQuote(stockQuote.quote),
}))
.filter((stockQuote): stockQuote is ValidStockQuote => stockQuote.quote !== null)
.map(({ quote, ...stockQuoteProps }) => ({
id: stockQuoteProps.id,
name: stockQuoteProps.name,
changePercent: quote["Global Quote"]["10. change percent"],
}))

return <StockDisplayRenderer quotes={validStockQuotes} />
export async function StockDisplay({ quotes }: { quotes: Quote[] }) {
const validQuotes = quotes.map((quote) => validateQuote(quote)) as Quote[]
return <StockDisplayRenderer quotes={validQuotes} />
}

function validateQuote(stockQuote: unknown) {
Expand All @@ -36,7 +13,13 @@ function validateQuote(stockQuote: unknown) {
}

const quoteSchema = z.object({
"Global Quote": z.object({
"10. change percent": z.string().transform((val) => parseFloat(val.slice(0, -1))),
}),
id: z.string(),
name: z.string(),
change: z.string().transform((val) => parseFloat(val.slice(0, -1))),
})

type Quote = {
id: string
name: string
change: number
}
2 changes: 1 addition & 1 deletion src/components/StockDisplay/StockDisplayRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StockQuote } from "./StockQuote"

export type Quote = { name: string; id: string; changePercent: number }
export type Quote = { name: string; id: string; change: number }

type StockDisplayRendererProps = {
quotes: Quote[]
Expand Down
4 changes: 2 additions & 2 deletions src/components/StockDisplay/StockQuote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { cn } from "@/utils/cn"
import { Quote } from "./StockDisplayRenderer"

export function StockQuote({ quote }: { quote: Quote }) {
const isNegative = quote.changePercent < 0
const isNegative = quote.change < 0
return (
<div className="flex items-center justify-center gap-4 border-r-2 border-slate-100 px-10 text-sm">
<span className="whitespace-nowrap font-medium">{quote.name}</span>
<span className={cn("flex items-center gap-1", isNegative ? "text-red-800" : "text-green-800")}>
{!isNegative && "+"}
{quote.changePercent.toFixed(2)}%
{quote.change.toFixed(2)}%
{isNegative ? <MoveDown className="mt-0.5 h-3 w-3" /> : <MoveUp className="mt-0.5 h-3 w-3" />}
</span>
</div>
Expand Down
5 changes: 2 additions & 3 deletions src/lib/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,12 @@ export async function getFooter(locale: Locale) {
}

export async function getHomepage(locale: Locale) {
const { homepages } = await graphqlFetch({
const { homepages, marketStock } = await graphqlFetch({
document: getHomepageQuery,
tags: ["HOMEPAGE", "CATEGORY", "ARTICLE"],
revalidate: 60 * 60 * 12, // 12h
variables: { locale },
})
return homepages[0] ?? null
return { ...homepages[0], marketStock }
}

export async function getHomepageMetadata(locale: Locale) {
Expand Down
6 changes: 1 addition & 5 deletions src/lib/queries/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@ export const getNavigationQuery = graphql(`

export const getHomepageQuery = graphql(`
query getHomepage($locales: [Locale!]!) {
marketStock
homepages(locales: $locales, first: 1) {
stockDailyQuotes {
id
name
quote
}
recentSectionTitle
trendingSectionTitle
highlightedCategoryTitle
Expand Down

0 comments on commit a5ccadb

Please sign in to comment.