From 65453f95f78e64cd86317a2be11e8185792d5385 Mon Sep 17 00:00:00 2001
From: Yasuaki Uechi <y@uechi.io>
Date: Tue, 6 Aug 2019 01:17:29 +0900
Subject: [PATCH] feat: app store

---
 api/services/appstore.js                 | 32 +++++++++++++++++++++
 web/public/locales/en/translation.json   |  9 +++---
 web/public/locales/ja/translation.json   |  9 +++---
 web/src/App.js                           |  2 ++
 web/src/components/Welcome.js            | 23 +++++++++++----
 web/src/components/cards/AppStoreCard.js | 36 ++++++++++++++++++++++++
 6 files changed, 97 insertions(+), 14 deletions(-)
 create mode 100644 api/services/appstore.js
 create mode 100644 web/src/components/cards/AppStoreCard.js

diff --git a/api/services/appstore.js b/api/services/appstore.js
new file mode 100644
index 0000000..df60089
--- /dev/null
+++ b/api/services/appstore.js
@@ -0,0 +1,32 @@
+const { send, sendError, fetch } = require('../util/http')
+
+module.exports = async (req, res) => {
+  const { query } = req.query
+
+  if (!query) {
+    return res.status(400).json({ error: 'no query given' })
+  }
+
+  const term = encodeURIComponent(query)
+  const country = 'us'
+  const limit = 3
+
+  try {
+    const response = await fetch(
+      `https://itunes.apple.com/search?media=software&entity=software,iPadSoftware,macSoftware,softwareDeveloper&country=${country}&limit=${limit}&term=${term}`,
+      'GET'
+    )
+    const body = await response.json()
+    const apps = body.results.map((app) => ({
+      id: app.trackId,
+      name: app.trackName,
+      kind: app.kind,
+      version: app.version,
+      price: app.price,
+      viewURL: app.trackViewUrl,
+    }))
+    send(res, { result: apps || [] })
+  } catch (err) {
+    sendError(res, err)
+  }
+}
diff --git a/web/public/locales/en/translation.json b/web/public/locales/en/translation.json
index 0f4f8cd..e160a5f 100644
--- a/web/public/locales/en/translation.json
+++ b/web/public/locales/en/translation.json
@@ -5,17 +5,18 @@
   "providers": {
     "domains": "Domains",
     "github": "Github Organization",
-    "githubSearch": "Github Repository",
     "npm": "npm",
     "pypi": "PyPI",
     "rubygems": "RubyGems",
     "rust": "Rust",
     "homebrew": "Homebrew",
-    "jsorg": "js.org",
-    "s3": "AWS S3",
+    "linux": "Linux",
+    "githubSearch": "Github Repository",
+    "appStore": "App Store",
     "twitter": "Twitter",
     "slack": "Slack",
-    "linux": "Linux"
+    "s3": "AWS S3",
+    "jsorg": "js.org"
   },
   "try": "How about"
 }
diff --git a/web/public/locales/ja/translation.json b/web/public/locales/ja/translation.json
index 368fac9..798e480 100644
--- a/web/public/locales/ja/translation.json
+++ b/web/public/locales/ja/translation.json
@@ -5,17 +5,18 @@
   "providers": {
     "domains": "ドメイン",
     "github": "Github Organization",
-    "githubSearch": "Github リポジトリ",
     "npm": "npm",
     "pypi": "PyPI",
     "rubygems": "RubyGems",
     "rust": "Rust",
     "homebrew": "Homebrew",
-    "jsorg": "js.org",
-    "s3": "AWS S3",
+    "linux": "Linux",
+    "githubSearch": "Github リポジトリ",
+    "appStore": "App Store",
     "twitter": "Twitter",
     "slack": "Slack",
-    "linux": "Linux"
+    "s3": "AWS S3",
+    "jsorg": "js.org"
   },
   "try": "これはどう?"
 }
diff --git a/web/src/App.js b/web/src/App.js
index b7b626d..e2500a1 100644
--- a/web/src/App.js
+++ b/web/src/App.js
@@ -12,6 +12,7 @@ import CratesioCard from './components/cards/CratesioCard'
 import HomebrewCard from './components/cards/HomebrewCard'
 import LinuxCard from './components/cards/LinuxCard'
 import GithubSearchCard from './components/cards/GithubSearchCard'
+import AppStoreCard from './components/cards/AppStoreCard'
 import TwitterCard from './components/cards/TwitterCard'
 import SlackCard from './components/cards/SlackCard'
 import S3Card from './components/cards/S3Card'
@@ -100,6 +101,7 @@ export default function App() {
               <HomebrewCard name={query} />
               <LinuxCard name={query} />
               <GithubSearchCard query={query} />
+              <AppStoreCard query={query} />
               <TwitterCard name={query} />
               <SlackCard name={query} />
               <S3Card name={query} />
diff --git a/web/src/components/Welcome.js b/web/src/components/Welcome.js
index 005be19..451a1cd 100644
--- a/web/src/components/Welcome.js
+++ b/web/src/components/Welcome.js
@@ -6,13 +6,15 @@ import { FaMapSigns } from 'react-icons/fa'
 import { FaGithub } from 'react-icons/fa'
 import { FaNpm } from 'react-icons/fa'
 import { FaPython } from 'react-icons/fa'
-import { IoIosBeer } from 'react-icons/io'
+import { FaGem } from 'react-icons/fa'
 import { DiRust } from 'react-icons/di'
-import { FaJsSquare } from 'react-icons/fa'
-import { FaAws } from 'react-icons/fa'
+import { IoIosBeer } from 'react-icons/io'
+import { FaLinux } from 'react-icons/fa'
+import { FaAppStore } from 'react-icons/fa'
 import { FaTwitter } from 'react-icons/fa'
 import { FaSlack } from 'react-icons/fa'
-import { FaGem } from 'react-icons/fa'
+import { FaAws } from 'react-icons/fa'
+import { FaJsSquare } from 'react-icons/fa'
 
 import { mobile } from '../util/css'
 
@@ -48,10 +50,13 @@ export default function Welcome() {
           <IoIosBeer /> {t('providers.homebrew')}
         </ListItem>
         <ListItem>
-          <FaJsSquare /> {t('providers.jsorg')}
+          <FaLinux /> {t('providers.linux')}
         </ListItem>
         <ListItem>
-          <FaAws /> {t('providers.s3')}
+          <FaGithub /> {t('providers.githubSearch')}
+        </ListItem>
+        <ListItem>
+          <FaAppStore /> {t('providers.appStore')}
         </ListItem>
         <ListItem>
           <FaTwitter /> {t('providers.twitter')}
@@ -59,6 +64,12 @@ export default function Welcome() {
         <ListItem>
           <FaSlack /> {t('providers.slack')}
         </ListItem>
+        <ListItem>
+          <FaAws /> {t('providers.s3')}
+        </ListItem>
+        <ListItem>
+          <FaJsSquare /> {t('providers.jsorg')}
+        </ListItem>
       </List>
     </Container>
   )
diff --git a/web/src/components/cards/AppStoreCard.js b/web/src/components/cards/AppStoreCard.js
new file mode 100644
index 0000000..bcb3a92
--- /dev/null
+++ b/web/src/components/cards/AppStoreCard.js
@@ -0,0 +1,36 @@
+import React from 'react'
+import useFetch from 'fetch-suspense'
+import { useTranslation } from 'react-i18next'
+import { FaAppStore } from 'react-icons/fa'
+
+import { Card, Result } from '../Cards'
+
+function Search({ query }) {
+  const term = encodeURIComponent(query)
+  const response = useFetch(`/availability/appstore/${term}`)
+  const apps = response.result
+
+  return (
+    <div>
+      {apps.map((app) => (
+        <Result
+          title={app.name}
+          message={`Price: ${app.price}`}
+          link={app.viewURL}
+          icon={<FaAppStore />}
+          key={app.id}
+        />
+      ))}
+    </div>
+  )
+}
+
+export default function AppStoreCard({ query }) {
+  const { t } = useTranslation()
+
+  return (
+    <Card title={t('providers.appStore')}>
+      <Search query={query} />
+    </Card>
+  )
+}