IGDV v3 migration (#125)
* Updated endpoints to use IGDB v3 * Updated computed props to match v3 changes * Moved ageRatings to getter + updated for v3 * Updated getters to support v3 changes * Moved all ratings images under same folder * Use new endpoints in actions * Compatibility updates * Null check * formatting * Load games in chunks of 10 to meet new API requirements * More compatibility changes * Use ids for New and standard 3DS, great job naming consoles nintendo! * Drop v2 suffix
|
@ -1,22 +1,25 @@
|
|||
const functions = require('firebase-functions');
|
||||
const axios = require('axios');
|
||||
|
||||
axios.defaults.headers.common['user-key'] = functions.config().igdb.key;
|
||||
|
||||
const igdbUrl = 'https://api-endpoint.igdb.com';
|
||||
const igdbV3Url = 'https://api-v3.igdb.com/';
|
||||
const igdbFields = 'id,name,slug,created_at,updated_at,summary,rating,category,player_perspectives,release_dates,name,cover,platforms,screenshots,videos,websites,esrb,pegi,themes.name,game.name&expand=game,themes,developers,publishers,game_engines,game_modes,genres,platforms,player_perspectives';
|
||||
const igdbV3Fields = 'fields alternative_name,character,collection,company,description,game,name,person,platform,popularity,published_at,test_dummy,theme;';
|
||||
const igdbFieldsMinimal = 'id,name,slug,rating,name,cover,release_dates';
|
||||
axios.defaults.headers.common['user-key'] = functions.config().igdbv3.key;
|
||||
|
||||
exports.search = functions.https.onRequest((req, res) => {
|
||||
res.set('Access-Control-Allow-Origin', "*")
|
||||
|
||||
const { searchText, platformId } = req.query;
|
||||
const { search, platform } = req.query;
|
||||
|
||||
axios.get(`${igdbUrl}/games/?search=${searchText}&fields=${igdbFields}&filter[platforms][eq]=${platformId}&limit=20&order=popularity:desc`)
|
||||
const data = `search "${search}"; fields id,name,slug,rating,name,cover.image_id; where platforms = (${platform});`
|
||||
|
||||
axios({
|
||||
url: 'https://api-v3.igdb.com/games',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
.catch((error) => { res.send(error) });
|
||||
});
|
||||
|
||||
exports.games = functions.https.onRequest((req, res) => {
|
||||
|
@ -24,9 +27,22 @@ exports.games = functions.https.onRequest((req, res) => {
|
|||
|
||||
const { games } = req.query;
|
||||
|
||||
axios.get(`${igdbUrl}/games/${games}/?fields=${igdbFieldsMinimal}`)
|
||||
if (!games) {
|
||||
res.status(400).send('missing param games');
|
||||
}
|
||||
|
||||
const data = `fields id,name,slug,rating,name,cover.image_id; where id = (${ games });`;
|
||||
|
||||
axios({
|
||||
url: 'https://api-v3.igdb.com/games',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
.catch((error) => { res.send(error) });
|
||||
});
|
||||
|
||||
exports.game = functions.https.onRequest((req, res) => {
|
||||
|
@ -34,9 +50,43 @@ exports.game = functions.https.onRequest((req, res) => {
|
|||
|
||||
const { gameId } = req.query;
|
||||
|
||||
axios.get(`${igdbUrl}/games/${gameId}/?fields=${igdbFields}`)
|
||||
if (!gameId) {
|
||||
res.status(400).send('missing param gameId');
|
||||
}
|
||||
|
||||
const data = `fields
|
||||
name,
|
||||
summary,
|
||||
cover.image_id,
|
||||
screenshots.image_id,
|
||||
player_perspectives.name,
|
||||
involved_companies.company.name,
|
||||
involved_companies.developer,
|
||||
involved_companies.publisher,
|
||||
release_dates.platform,
|
||||
release_dates.date,
|
||||
websites.category,
|
||||
websites.url,
|
||||
age_ratings.*,
|
||||
videos.video_id,
|
||||
rating,
|
||||
genres.name,
|
||||
platforms.name,
|
||||
game_modes.name,
|
||||
time_to_beat;
|
||||
|
||||
where id = ${ gameId };`;
|
||||
|
||||
axios({
|
||||
url: 'https://api-v3.igdb.com/games',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
.catch((error) => { res.send(error) });
|
||||
});
|
||||
|
||||
exports.email = functions.https.onRequest((req, res) => {
|
||||
|
@ -66,76 +116,5 @@ exports.email = functions.https.onRequest((req, res) => {
|
|||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
.catch((error) => { res.send(error) });
|
||||
});
|
||||
|
||||
exports.searchV2 = functions.https.onRequest((req, res) => {
|
||||
res.set('Access-Control-Allow-Origin', "*")
|
||||
|
||||
const { search, platform } = req.query;
|
||||
|
||||
const data = `search "${search}"; fields id,name,slug,rating,name,cover.image_id; where platforms = (${platform});`
|
||||
|
||||
axios({
|
||||
url: 'https://api-v3.igdb.com/games',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'user-key': '3b516a46c3af209bb6e287e9090d720c'
|
||||
},
|
||||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
});
|
||||
|
||||
exports.gameV2 = functions.https.onRequest((req, res) => {
|
||||
res.set('Access-Control-Allow-Origin', "*")
|
||||
|
||||
const { gameId } = req.query;
|
||||
|
||||
if (!gameId) {
|
||||
res.status(400).send('missing param gameId');
|
||||
}
|
||||
|
||||
const data = `fields *; where id = ${ gameId };`;
|
||||
|
||||
axios({
|
||||
url: 'https://api-v3.igdb.com/games',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'user-key': '3b516a46c3af209bb6e287e9090d720c'
|
||||
},
|
||||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
});
|
||||
|
||||
exports.gamesV2 = functions.https.onRequest((req, res) => {
|
||||
res.set('Access-Control-Allow-Origin', "*")
|
||||
|
||||
const { gameId } = req.query;
|
||||
|
||||
if (!gameId) {
|
||||
res.status(400).send('missing param gameId');
|
||||
}
|
||||
|
||||
const data = `fields id,name,slug,rating,name,cover.url; where id = (${ gameId });`;
|
||||
|
||||
axios({
|
||||
url: 'https://api-v3.igdb.com/games',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'user-key': '3b516a46c3af209bb6e287e9090d720c'
|
||||
},
|
||||
data,
|
||||
})
|
||||
.then(({ data }) => { res.status(200).send(data) })
|
||||
.catch(() => { res.send(400) });
|
||||
});
|
||||
|
||||
|
||||
// TODO: merge search and game, swap out or request fields in FE
|
|
@ -59,10 +59,10 @@ export default {
|
|||
},
|
||||
|
||||
coverUrl() {
|
||||
const url = 'https://images.igdb.com/igdb/image/upload/t_cover_small_2x/';
|
||||
const game = this.games[this.gameId];
|
||||
|
||||
return this.games && this.games[this.gameId].cover
|
||||
? `${url}${this.games[this.gameId].cover.cloudinary_id}.jpg`
|
||||
return game.cover && game.cover.image_id
|
||||
? `https://images.igdb.com/igdb/image/upload/t_cover_small_2x/${game.cover.image_id}.jpg`
|
||||
: '/static/no-image.jpg';
|
||||
},
|
||||
|
||||
|
|
|
@ -41,10 +41,10 @@ export default {
|
|||
},
|
||||
|
||||
coverUrl() {
|
||||
const url = 'https://images.igdb.com/igdb/image/upload/t_cover_small_2x/';
|
||||
const game = this.games[this.id];
|
||||
|
||||
return this.games && this.games[this.id].cover
|
||||
? `${url}${this.games[this.id].cover.cloudinary_id}.jpg`
|
||||
return game.cover && game.cover.image_id
|
||||
? `https://images.igdb.com/igdb/image/upload/t_cover_small_2x/${game.cover.image_id}.jpg`
|
||||
: '/static/no-image.jpg';
|
||||
},
|
||||
},
|
||||
|
|
|
@ -2,46 +2,32 @@
|
|||
<div :class="['game-header', { dark: darkModeEnabled}]">
|
||||
<img :src="coverUrl" :alt="game.name" class="game-cover" />
|
||||
|
||||
<div class="game-rating" v-if="hasRatings">
|
||||
<div class="game-rating" v-if="game.age_ratings">
|
||||
<img
|
||||
v-if="game.esrb"
|
||||
:src='`/static/img/esrb/${igdb.esrb[game.esrb.rating]}.png`'
|
||||
:alt="game.esrb.synopsis"
|
||||
>
|
||||
|
||||
<img
|
||||
v-if="game.pegi"
|
||||
:src='`/static/img/pegi/${igdb.pegi[game.pegi.rating]}.png`'
|
||||
:alt="game.pegi.synopsis"
|
||||
>
|
||||
v-for="{ rating, synopsis, id } in game.age_ratings"
|
||||
:key="id"
|
||||
:src='`/static/img/ageRatings/${ageRatings[rating]}.png`'
|
||||
:alt="synopsis"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import igdb from '@/shared/igdb';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
|
||||
|
||||
export default {
|
||||
props: {
|
||||
gameId: [Number, String],
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
igdb,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['game', 'platform']),
|
||||
...mapGetters(['darkModeEnabled']),
|
||||
...mapGetters(['darkModeEnabled', 'ageRatings']),
|
||||
|
||||
coverUrl() {
|
||||
const url = 'https://images.igdb.com/igdb/image/upload/t_cover_big/';
|
||||
return this.game && this.game.cover
|
||||
? `${url}${this.game.cover.cloudinary_id}.jpg`
|
||||
? `https://images.igdb.com/igdb/image/upload/t_cover_small_2x/${this.game.cover.image_id}.jpg`
|
||||
: '/static/no-image.jpg';
|
||||
},
|
||||
|
||||
|
@ -50,10 +36,6 @@ export default {
|
|||
? `background: url(${this.getImageUrl(this.game.screenshots[0].cloudinary_id)}) center center no-repeat; background-size: cover;`
|
||||
: '';
|
||||
},
|
||||
|
||||
hasRatings() {
|
||||
return this.game.esrb || this.game.pegi;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -96,6 +78,8 @@ export default {
|
|||
|
||||
.game-rating {
|
||||
margin-top: $gp;
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
|
||||
img {
|
||||
height: 60px;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<template lang="html">
|
||||
<div v-if="game" class="review-box">
|
||||
<div class="info">
|
||||
<!-- TODO: get icons for everything -->
|
||||
<section v-if="playerPerspectives">
|
||||
<strong>Perspective</strong> {{ playerPerspectives }}
|
||||
</section>
|
||||
|
@ -14,6 +15,8 @@
|
|||
</section>
|
||||
|
||||
<section v-if="gamePlatforms">
|
||||
<!-- TODO: show current platform icon,
|
||||
and also show "available on these other platforms" -->
|
||||
<strong>{{ $t('gameDetail.gamePlatforms') }}</strong> {{ gamePlatforms }}
|
||||
</section>
|
||||
|
||||
|
@ -25,15 +28,17 @@
|
|||
<strong>{{ $t('gameDetail.publishers') }}</strong> {{ publishers }}
|
||||
</section>
|
||||
|
||||
<!-- <section v-if="releaseDate">
|
||||
<strong>Release date</strong> {{ releaseDate }}
|
||||
</section> -->
|
||||
<!-- <game-links /> -->
|
||||
<section v-if="releaseDate">
|
||||
<strong>Release date</strong> {{ moment.unix(releaseDate).format('ll') }}
|
||||
</section>
|
||||
|
||||
<game-links />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import GameLinks from '@/components/GameDetail/GameLinks';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
|
||||
|
@ -42,6 +47,12 @@ export default {
|
|||
GameLinks,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
moment,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState([
|
||||
'game',
|
||||
|
@ -53,6 +64,7 @@ export default {
|
|||
'developers',
|
||||
'gameModes',
|
||||
'gamePlatforms',
|
||||
'releaseDate',
|
||||
'genres',
|
||||
'publishers',
|
||||
]),
|
||||
|
|
|
@ -43,20 +43,26 @@ export default {
|
|||
// eslint-disable-next-line
|
||||
return this.game.screenshots
|
||||
? this.game.screenshots.map((image, index) => {
|
||||
const url = 'https://images.igdb.com/igdb/image/upload/t_screenshot_huge/';
|
||||
const href = `https://images.igdb.com/igdb/image/upload/t_screenshot_huge/${image.image_id}.jpg`;
|
||||
|
||||
return {
|
||||
href: `${url}${image.cloudinary_id}.jpg`,
|
||||
href,
|
||||
title: `${this.game.name} (${index + 1} of ${this.game.screenshots.length})`,
|
||||
};
|
||||
})
|
||||
: null;
|
||||
},
|
||||
|
||||
coverUrl() {
|
||||
return this.game && this.game.cover
|
||||
? `https://images.igdb.com/igdb/image/upload/t_cover_small_2x/${this.game.cover.image_id}.jpg`
|
||||
: '/static/no-image.jpg';
|
||||
},
|
||||
|
||||
thumbnails() {
|
||||
// eslint-disable-next-line
|
||||
return this.game.screenshots ? this.game.screenshots.map((image) => {
|
||||
return `https://images.igdb.com/igdb/image/upload/t_thumb/${image.cloudinary_id}.jpg`;
|
||||
return `https://images.igdb.com/igdb/image/upload/t_thumb/${image.image_id}.jpg`;
|
||||
}) : null;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -34,7 +34,10 @@
|
|||
@update="updateLists"
|
||||
/>
|
||||
|
||||
<div :class="`game-grid game-grid-${listIndex}`" v-if="view === 'grid' && !editing && !searching">
|
||||
<div
|
||||
:class="`game-grid game-grid-${listIndex}`"
|
||||
v-if="view === 'grid' && !editing && !searching"
|
||||
>
|
||||
<component
|
||||
v-for="game in games"
|
||||
:is="gameCardComponent"
|
||||
|
@ -158,7 +161,7 @@ export default {
|
|||
},
|
||||
|
||||
gameCardComponent() {
|
||||
return this.view
|
||||
return this.view && Object.keys(this.gameCardComponents).includes(this.view)
|
||||
? this.gameCardComponents[this.view]
|
||||
: 'GameCardDefault';
|
||||
},
|
||||
|
|
|
@ -82,6 +82,7 @@ import Panel from '@/components/Panel/Panel';
|
|||
import GameDetail from '@/pages/GameDetail';
|
||||
import Modal from '@/components/Modal/Modal';
|
||||
// import DevDebug from '@/components/DevDebug/DevDebug';
|
||||
import { chunk } from 'lodash';
|
||||
import List from '@/components/Lists/List';
|
||||
import draggable from 'vuedraggable';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
|
@ -214,6 +215,7 @@ export default {
|
|||
if (this.list) {
|
||||
const gameList = [];
|
||||
|
||||
// TODO: refactor this to use reduce or map
|
||||
this.list.forEach((list) => {
|
||||
if (list && list.games.length) {
|
||||
list.games.forEach((id) => {
|
||||
|
@ -225,15 +227,19 @@ export default {
|
|||
});
|
||||
|
||||
if (gameList.length > 0) {
|
||||
this.loading = true;
|
||||
const chunkedGameList = chunk(gameList, 10);
|
||||
|
||||
this.$store.dispatch('LOAD_GAMES', gameList)
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.$bus.$emit('TOAST', { message: 'Error loading game', type: 'error' });
|
||||
});
|
||||
chunkedGameList.forEach((partialGameList) => {
|
||||
this.loading = true;
|
||||
|
||||
this.$store.dispatch('LOAD_GAMES', partialGameList.toString())
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.$bus.$emit('TOAST', { message: 'Error loading game', type: 'error' });
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<template lang="html">
|
||||
<div class="game-detail-wrapper">
|
||||
<game-detail-placeholder v-if="!game" :id="id" />
|
||||
|
||||
<div class="game-detail" v-else :class="{ dark: darkModeEnabled }">
|
||||
<div class="game-detail" v-if="game" :class="{ dark: darkModeEnabled }">
|
||||
<div class="game-hero" :style="style" />
|
||||
|
||||
<div class="game-detail-container">
|
||||
|
@ -48,10 +47,12 @@
|
|||
<p class="game-description" v-html="game.summary" />
|
||||
|
||||
<game-notes />
|
||||
<!-- Time to beat
|
||||
{{ new Date(game.time_to_beat * 1000)
|
||||
.toISOString().substr(11, 8) }} -->
|
||||
|
||||
<game-review-box />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<game-screenshots />
|
||||
|
@ -59,6 +60,8 @@
|
|||
<igdb-credit gray />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<game-detail-placeholder v-else :id="id" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -105,9 +108,15 @@ export default {
|
|||
},
|
||||
|
||||
style() {
|
||||
return this.game && this.game.screenshots
|
||||
? `background: url(${this.getImageUrl(this.game.screenshots[0].cloudinary_id)}) center center no-repeat; background-size: cover;`
|
||||
const screenshot = this.game.screenshots && this.game.screenshots.length > 0
|
||||
? this.game.screenshots[0]
|
||||
: null;
|
||||
|
||||
const screenshotUrl = screenshot && screenshot.image_id
|
||||
? `https://images.igdb.com/igdb/image/upload/t_screenshot_big/${screenshot.image_id}.jpg`
|
||||
: '';
|
||||
|
||||
return `background: url('${screenshotUrl}') center center no-repeat; background-size: cover;`;
|
||||
},
|
||||
|
||||
activePlatform() {
|
||||
|
@ -119,10 +128,8 @@ export default {
|
|||
},
|
||||
|
||||
coverUrl() {
|
||||
const url = 'https://images.igdb.com/igdb/image/upload/t_cover_small_2x/';
|
||||
|
||||
return this.game && this.game.cover
|
||||
? `${url}${this.game.cover.cloudinary_id}.jpg`
|
||||
return this.game.cover && this.game.cover.image_id
|
||||
? `https://images.igdb.com/igdb/image/upload/t_cover_small_2x/${this.game.cover.image_id}.jpg`
|
||||
: '/static/no-image.jpg';
|
||||
},
|
||||
},
|
||||
|
@ -132,12 +139,6 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
getImageUrl(cloudinaryId) {
|
||||
return cloudinaryId
|
||||
? `https://images.igdb.com/igdb/image/upload/t_screenshot_huge/${cloudinaryId}.jpg`
|
||||
: null;
|
||||
},
|
||||
|
||||
removeTag(tagName) {
|
||||
this.$store.commit('REMOVE_GAME_TAG', { tagName, gameId: this.game.id });
|
||||
this.$bus.$emit('SAVE_TAGS', this.tags);
|
||||
|
|
|
@ -1,20 +1,4 @@
|
|||
export default {
|
||||
pegi: {
|
||||
1: '3',
|
||||
2: '7',
|
||||
3: '12',
|
||||
4: '16',
|
||||
5: '18',
|
||||
},
|
||||
esrb: {
|
||||
1: 'RP',
|
||||
2: 'EC',
|
||||
3: 'E',
|
||||
4: 'E10+',
|
||||
5: 'T',
|
||||
6: 'M',
|
||||
7: 'AO',
|
||||
},
|
||||
linkTypes: {
|
||||
1: 'official',
|
||||
2: 'wikia',
|
||||
|
|
|
@ -192,7 +192,7 @@ export default [
|
|||
{
|
||||
name: 'Nintendo 3DS',
|
||||
code: 'n3ds',
|
||||
id: 37,
|
||||
id: '37,137',
|
||||
generation: 8,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -45,32 +45,11 @@ export default {
|
|||
|
||||
SEARCH({ commit, state }, searchText) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get(`${FIREBASE_URL}/search?searchText=${searchText}&platformId=${state.platform.id}`)
|
||||
axios.get(`${FIREBASE_URL}/search?search=${searchText}&platform=${state.platform.id}`)
|
||||
.then(({ data }) => {
|
||||
const originalData = data.slice();
|
||||
if (state.platform.id === 37) {
|
||||
// TODO: specify platform ids in platforms file,
|
||||
// let endpoint handle multiple ids
|
||||
axios.get(`${FIREBASE_URL}/search?searchText=${searchText}&platformId=137`)
|
||||
.then((response) => {
|
||||
const joinedData = [
|
||||
...originalData,
|
||||
...response.data,
|
||||
];
|
||||
|
||||
const ids = [...new Set(joinedData.map(({ id }) => id))];
|
||||
|
||||
const unique = ids.map(e => joinedData.find(({ id }) => id === e));
|
||||
|
||||
commit('SET_SEARCH_RESULTS', unique);
|
||||
commit('CACHE_GAME_DATA', unique);
|
||||
resolve();
|
||||
}).catch(reject);
|
||||
} else {
|
||||
commit('SET_SEARCH_RESULTS', data);
|
||||
commit('CACHE_GAME_DATA', data);
|
||||
resolve();
|
||||
}
|
||||
commit('SET_SEARCH_RESULTS', data);
|
||||
commit('CACHE_GAME_DATA', data);
|
||||
resolve();
|
||||
}).catch(reject);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,17 +1,44 @@
|
|||
export default {
|
||||
// eslint-disable-next-line
|
||||
ageRatings: () => {
|
||||
return {
|
||||
1: '3',
|
||||
2: '7',
|
||||
3: '12',
|
||||
4: '16',
|
||||
5: '18',
|
||||
6: 'RP',
|
||||
7: 'EC',
|
||||
8: 'E',
|
||||
9: 'E10',
|
||||
10: 'T',
|
||||
11: 'M',
|
||||
12: 'AO',
|
||||
};
|
||||
},
|
||||
|
||||
releaseDate: (state) => {
|
||||
// eslint-disable-next-line
|
||||
const releaseDate = state.game.release_dates.filter(({ platform }) => state.platform.id === platform);
|
||||
|
||||
return releaseDate && releaseDate.length
|
||||
? releaseDate[0].date
|
||||
: null;
|
||||
},
|
||||
|
||||
developers: (state) => {
|
||||
const developers = state.game.developers;
|
||||
const developers = state.game.involved_companies.filter(({ developer }) => developer);
|
||||
|
||||
return developers
|
||||
? developers.map(developer => developer.name).join(', ')
|
||||
? developers.map(publisher => publisher.company.name).join(', ')
|
||||
: null;
|
||||
},
|
||||
|
||||
publishers: (state) => {
|
||||
const publishers = state.game.publishers;
|
||||
const publishers = state.game.involved_companies.filter(({ publisher }) => publisher);
|
||||
|
||||
return publishers
|
||||
? publishers.map(publisher => publisher.name).join(', ')
|
||||
? publishers.map(publisher => publisher.company.name).join(', ')
|
||||
: null;
|
||||
},
|
||||
|
||||
|
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |