From 99b9519ab727efba7eba024a763c1b37c81578c9 Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Mon, 4 Dec 2023 13:35:01 -0700 Subject: [PATCH] Show dummy search results. --- assets/js/react/App.tsx | 11 +- assets/js/react/components/CaptionImage.tsx | 27 --- assets/js/react/components/FilterScroll.tsx | 16 +- assets/js/react/components/SearchResult.tsx | 41 ++++ assets/js/react/pages/Search.tsx | 91 +++++---- assets/js/react/types/Coach.ts | 9 + assets/js/react/types/Query.ts | 3 - assets/js/react/types/SearchParams.ts | 10 + assets/package-lock.json | 190 ++++++++++++++++++ assets/package.json | 2 + lib/boardwise/coach.ex | 21 -- lib/boardwise/coaches.ex | 5 +- lib/boardwise/coaches/coach.ex | 17 +- lib/boardwise_web/controllers/coach_json.ex | 2 + .../20231204221124_name_image_url.exs | 12 ++ 15 files changed, 347 insertions(+), 110 deletions(-) delete mode 100644 assets/js/react/components/CaptionImage.tsx create mode 100644 assets/js/react/components/SearchResult.tsx create mode 100644 assets/js/react/types/Coach.ts delete mode 100644 assets/js/react/types/Query.ts create mode 100644 assets/js/react/types/SearchParams.ts delete mode 100644 lib/boardwise/coach.ex create mode 100644 priv/repo/migrations/20231204221124_name_image_url.exs diff --git a/assets/js/react/App.tsx b/assets/js/react/App.tsx index 9453abb..93280c3 100644 --- a/assets/js/react/App.tsx +++ b/assets/js/react/App.tsx @@ -1,13 +1,18 @@ import * as React from "react" import { RouterProvider } from "react-router-dom" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { RootLayout } from "./components/RootLayout" import { router } from "./router" +const queryClient = new QueryClient() + export default function App() { return ( - - - + + + + + ) } diff --git a/assets/js/react/components/CaptionImage.tsx b/assets/js/react/components/CaptionImage.tsx deleted file mode 100644 index e0b6fe7..0000000 --- a/assets/js/react/components/CaptionImage.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from "react" - -interface CaptionImageProps { - title?: string - subtitle?: string - src: string -} - -export function CaptionImage({ title, subtitle, src }: CaptionImageProps) { - return ( -
- -
- {title && ( -

- {title} -

- )} - {subtitle &&

{subtitle}

} -
-
- ) -} diff --git a/assets/js/react/components/FilterScroll.tsx b/assets/js/react/components/FilterScroll.tsx index b79c544..57c43f2 100644 --- a/assets/js/react/components/FilterScroll.tsx +++ b/assets/js/react/components/FilterScroll.tsx @@ -1,7 +1,7 @@ import * as React from "react" import clsx from "clsx" -import type { Query } from "../types/Query" +import type { SearchParams } from "../types/SearchParams" import FilterIcon from "../icons/Filter" import RightArrowIcon from "../icons/RightArrow" @@ -11,8 +11,8 @@ import { Button } from "./Button" interface FilterOption { title: string Icon: ({ ...props }: { [x: string]: any }) => React.JSX.Element - enable: (q: Query) => Query - isEnabled: (q: Query) => boolean + enable: (p: SearchParams) => SearchParams + isEnabled: (p: SearchParams) => boolean } const filters: FilterOption[] = [ @@ -33,12 +33,12 @@ enum Direction { } interface FilterScrollProps { - query: Query + params: SearchParams onModal: () => void - onEnable: (q: Query) => void + onSelect: (p: SearchParams) => void } -export function FilterScroll({ query, onModal, onEnable }: FilterScrollProps) { +export function FilterScroll({ params, onModal, onSelect }: FilterScrollProps) { const viewport = React.useRef(null) const [isFlush, setIsFlush] = React.useState([true, false]) @@ -67,9 +67,9 @@ export function FilterScroll({ query, onModal, onEnable }: FilterScrollProps) {
onEnable(e.enable({ ...query }))} + onClick={() => onSelect(e.enable({ ...params }))} > {e.title} diff --git a/assets/js/react/components/SearchResult.tsx b/assets/js/react/components/SearchResult.tsx new file mode 100644 index 0000000..32f24fa --- /dev/null +++ b/assets/js/react/components/SearchResult.tsx @@ -0,0 +1,41 @@ +import * as React from "react" +import clsx from "clsx" + +type SearchResultProps = { + title?: string + subtitle?: string + src?: string +} & React.ComponentPropsWithoutRef<"div"> + +export function SearchResult({ + title, + subtitle, + src, + className, + ...props +}: SearchResultProps) { + return ( +
+ +
+ {title ? ( +

+ {title} +

+ ) : null} + {subtitle ? ( +

{subtitle}

+ ) : null} +
+
+ ) +} diff --git a/assets/js/react/pages/Search.tsx b/assets/js/react/pages/Search.tsx index 5efee9b..01b7ffc 100644 --- a/assets/js/react/pages/Search.tsx +++ b/assets/js/react/pages/Search.tsx @@ -1,63 +1,68 @@ import * as React from "react" +import axios from "axios" +import { useQuery } from "@tanstack/react-query" -import type { Query } from "../types/Query" +import type { Coach } from "../types/Coach" +import { type SearchParams, defaultSearchParams } from "../types/SearchParams" -import { CaptionImage } from "../components/CaptionImage" import { Container } from "../components/Container" import { FadeIn, FadeInStagger } from "../components/FadeIn" import { FallbackMessage } from "../components/FallbackMessage" import { FilterScroll } from "../components/FilterScroll" import { Loading } from "../components/Loading" +import { SearchResult } from "../components/SearchResult" -const FIDE_RATING_MIN = 1500 -const FIDE_RATING_MAX = 3200 +function SearchResults() { + const { isLoading, isError, data } = useQuery({ + queryKey: ["coaches"], + queryFn: async () => { + const response = await axios.get<{ data: Coach[] }>("/api/coaches/") + return response.data.data + }, + }) -interface Coach { - id: string - imageUrl: string - name: string - title: string - slug: string -} + if (isLoading) { + return + } -const defaultQuery: Query = { - fideRating: [FIDE_RATING_MIN, FIDE_RATING_MAX], + if (isError) { + return ( + + ) + } + + return ( + + {data?.map((coach, index) => ( + + + + ))} + + ) } export function Search() { - const [query, setQuery] = React.useState(defaultQuery) - const [loading, setLoading] = React.useState(true) - const [coaches, setCoaches] = React.useState([]) + const [searchParams, setSearchParams] = React.useState(defaultSearchParams) return ( - {}} /> - - {coaches.length > 0 ? ( - - {coaches.map((coach, index) => ( - - - - ))} - - ) : ( - - )} - + {}} + /> + ) } diff --git a/assets/js/react/types/Coach.ts b/assets/js/react/types/Coach.ts new file mode 100644 index 0000000..1e18501 --- /dev/null +++ b/assets/js/react/types/Coach.ts @@ -0,0 +1,9 @@ +export type Coach = { + site: string + username: string + name: string | null + image_url: string | null + rapid: number | null + blitz: number | null + bullet: number | null +} diff --git a/assets/js/react/types/Query.ts b/assets/js/react/types/Query.ts deleted file mode 100644 index 0dcb14a..0000000 --- a/assets/js/react/types/Query.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type Query = { - fideRating: [number, number] -} diff --git a/assets/js/react/types/SearchParams.ts b/assets/js/react/types/SearchParams.ts new file mode 100644 index 0000000..77204c1 --- /dev/null +++ b/assets/js/react/types/SearchParams.ts @@ -0,0 +1,10 @@ +export type SearchParams = { + fideRating: [number, number] +} + +const FIDE_RATING_MIN = 1500 +const FIDE_RATING_MAX = 3200 + +export const defaultSearchParams: SearchParams = { + fideRating: [FIDE_RATING_MIN, FIDE_RATING_MAX], +} diff --git a/assets/package-lock.json b/assets/package-lock.json index 0153a92..f9128d6 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@mui/base": "^5.0.0-beta.25", + "@tanstack/react-query": "^5.12.2", + "axios": "^1.6.2", "clsx": "^2.0.0", "framer-motion": "^10.16.12", "react": "^18.2.0", @@ -192,6 +194,30 @@ "node": ">=14.0.0" } }, + "node_modules/@tanstack/query-core": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.12.1.tgz", + "integrity": "sha512-WbZztNmKq0t6QjdNmHzezbi/uifYo9j6e2GLJkodsYaYUlzMbAp91RDyeHkIZrm7EfO4wa6Sm5sxJZm5SPlh6w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.12.2.tgz", + "integrity": "sha512-BeWZu8zVFH20oRc+S/K9ADPgWjEzP/XQCGBNz5IbApUwPQAdwkQYbXODVL5AyAlWiSxhx+P2xlARPBApj2Yrog==", + "dependencies": { + "@tanstack/query-core": "5.12.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, "node_modules/@types/history": { "version": "4.7.11", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", @@ -250,6 +276,21 @@ "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", "devOptional": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/clsx": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", @@ -258,12 +299,63 @@ "node": ">=6" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "devOptional": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/framer-motion": { "version": "10.16.12", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.12.tgz", @@ -303,6 +395,25 @@ "loose-envify": "cli.js" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -326,6 +437,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -498,6 +614,19 @@ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz", "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==" }, + "@tanstack/query-core": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.12.1.tgz", + "integrity": "sha512-WbZztNmKq0t6QjdNmHzezbi/uifYo9j6e2GLJkodsYaYUlzMbAp91RDyeHkIZrm7EfO4wa6Sm5sxJZm5SPlh6w==" + }, + "@tanstack/react-query": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.12.2.tgz", + "integrity": "sha512-BeWZu8zVFH20oRc+S/K9ADPgWjEzP/XQCGBNz5IbApUwPQAdwkQYbXODVL5AyAlWiSxhx+P2xlARPBApj2Yrog==", + "requires": { + "@tanstack/query-core": "5.12.1" + } + }, "@types/history": { "version": "4.7.11", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", @@ -556,17 +685,60 @@ "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", "devOptional": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "clsx": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "devOptional": true }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "framer-motion": { "version": "10.16.12", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.12.tgz", @@ -589,6 +761,19 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -611,6 +796,11 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", diff --git a/assets/package.json b/assets/package.json index 140081e..f94ddb6 100644 --- a/assets/package.json +++ b/assets/package.json @@ -3,6 +3,8 @@ "version": "0.1.0", "dependencies": { "@mui/base": "^5.0.0-beta.25", + "@tanstack/react-query": "^5.12.2", + "axios": "^1.6.2", "clsx": "^2.0.0", "framer-motion": "^10.16.12", "react": "^18.2.0", diff --git a/lib/boardwise/coach.ex b/lib/boardwise/coach.ex deleted file mode 100644 index 04df005..0000000 --- a/lib/boardwise/coach.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule BoardWise.Coach do - use Ecto.Schema - import Ecto.Changeset - - schema "coaches" do - field :blitz, :integer - field :bullet, :integer - field :rapid, :integer - field :site, :string - field :username, :string - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(coach, attrs) do - coach - |> cast(attrs, [:site, :username, :rapid, :blitz, :bullet]) - |> validate_required([:site, :username, :rapid, :blitz, :bullet]) - end -end diff --git a/lib/boardwise/coaches.ex b/lib/boardwise/coaches.ex index 2c92183..9bb1a09 100644 --- a/lib/boardwise/coaches.ex +++ b/lib/boardwise/coaches.ex @@ -20,7 +20,10 @@ defmodule BoardWise.Coaches do """ def list_coaches do - Repo.all(Coach, prefix: @prefix) + Coach + |> limit(6) + |> where(site: "lichess") + |> Repo.all(prefix: @prefix) end @doc """ diff --git a/lib/boardwise/coaches/coach.ex b/lib/boardwise/coaches/coach.ex index 87c4e95..43f5c7c 100644 --- a/lib/boardwise/coaches/coach.ex +++ b/lib/boardwise/coaches/coach.ex @@ -15,18 +15,27 @@ defmodule BoardWise.Coaches.Coach do import Ecto.Changeset schema "export" do + field :site, :string + field :username, :string + field :name, :string + field :image_url, :string field :blitz, :integer field :bullet, :integer field :rapid, :integer - - field :site, :string - field :username, :string end @doc false def changeset(coach, attrs) do coach - |> cast(attrs, [:rapid, :blitz, :bullet, :site, :username]) + |> cast(attrs, [ + :site, + :username, + :name, + :image_url, + :rapid, + :blitz, + :bullet + ]) |> validate_required([:site, :username]) |> unique_constraint(:site_username_unique, name: :site_username_unique) end diff --git a/lib/boardwise_web/controllers/coach_json.ex b/lib/boardwise_web/controllers/coach_json.ex index a161e06..513f636 100644 --- a/lib/boardwise_web/controllers/coach_json.ex +++ b/lib/boardwise_web/controllers/coach_json.ex @@ -12,6 +12,8 @@ defmodule BoardWiseWeb.CoachJSON do %{ site: coach.site, username: coach.username, + name: coach.name, + image_url: coach.image_url, rapid: coach.rapid, blitz: coach.blitz, bullet: coach.bullet diff --git a/priv/repo/migrations/20231204221124_name_image_url.exs b/priv/repo/migrations/20231204221124_name_image_url.exs new file mode 100644 index 0000000..5504802 --- /dev/null +++ b/priv/repo/migrations/20231204221124_name_image_url.exs @@ -0,0 +1,12 @@ +defmodule BoardWise.Repo.Migrations.NameImageUrl do + use Ecto.Migration + + @prefix "coach_scraper" + + def change do + alter table(:export, prefix: @prefix) do + add :name, :string + add :image_url, :string + end + end +end