From 777563940e14a33849721b92ad6c093f80e9d127 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 02:44:48 -0800 Subject: [PATCH 01/89] Fix tab URLs The app was crashing when you went to another tab on new pages because the rewrites were only configured for URLs with shortcodes --- next.config.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/next.config.js b/next.config.js index 93967c18..24e220ba 100644 --- a/next.config.js +++ b/next.config.js @@ -15,6 +15,18 @@ module.exports = { source: '/', destination: '/new', }, + { + source: '/characters', + destination: '/new', + }, + { + source: '/summons', + destination: '/new', + }, + { + source: '/weapons', + destination: '/new', + }, { source: '/p/:shortcode/characters', destination: '/p/:shortcode', From 0c8102c66fb0309d2a2c9ff5d906d716c31d6ef6 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 14:43:01 -0800 Subject: [PATCH 02/89] Basic error handling for API errors in SSR --- pages/[username].tsx | 79 ++++++++++++++------------- pages/new/index.tsx | 49 +++++++++-------- pages/p/[party].tsx | 120 +++++++++++++++++++++--------------------- pages/saved.tsx | 61 +++++++++++---------- pages/teams.tsx | 59 +++++++++++---------- utils/reportError.tsx | 20 +++++++ 6 files changed, 213 insertions(+), 175 deletions(-) create mode 100644 utils/reportError.tsx diff --git a/pages/[username].tsx b/pages/[username].tsx index 805d3acb..37ac466b 100644 --- a/pages/[username].tsx +++ b/pages/[username].tsx @@ -15,6 +15,7 @@ import organizeRaids from '~utils/organizeRaids' import useDidMountEffect from '~utils/useDidMountEffect' import { elements, allElement } from '~data/elements' import { emptyPaginationObject } from '~utils/emptyStates' +import { printError } from '~utils/reportError' import GridRep from '~components/GridRep' import GridRepCollection from '~components/GridRepCollection' @@ -350,50 +351,54 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex // Set headers for server-side requests setUserToken(req, res) - // Fetch and organize raids - let { raids, sortedRaids } = await api.endpoints.raids - .getAll() - .then((response) => organizeRaids(response.data)) + try { + // Fetch and organize raids + let { raids, sortedRaids } = await api.endpoints.raids + .getAll() + .then((response) => organizeRaids(response.data)) - // Create filter object - const filters: FilterObject = extractFilters(query, raids) - const params = { - params: { ...filters }, - } + // Create filter object + const filters: FilterObject = extractFilters(query, raids) + const params = { + params: { ...filters }, + } - // Set up empty variables - let user: User | null = null - let teams: Party[] | null = null - let meta: PaginationObject = emptyPaginationObject + // Set up empty variables + let user: User | null = null + let teams: Party[] | null = null + let meta: PaginationObject = emptyPaginationObject - // Perform a request only if we received a username - if (query.username) { - const response = await api.endpoints.users.getOne({ - id: query.username, - params, - }) + // Perform a request only if we received a username + if (query.username) { + const response = await api.endpoints.users.getOne({ + id: query.username, + params, + }) - // Assign values to pass to props - user = response.data.profile + // Assign values to pass to props + user = response.data.profile - if (response.data.profile.parties) teams = response.data.profile.parties - else teams = [] + if (response.data.profile.parties) teams = response.data.profile.parties + else teams = [] - meta.count = response.data.meta.count - meta.totalPages = response.data.meta.total_pages - meta.perPage = response.data.meta.per_page - } + meta.count = response.data.meta.count + meta.totalPages = response.data.meta.total_pages + meta.perPage = response.data.meta.per_page + } - return { - props: { - user: user, - teams: teams, - meta: meta, - raids: raids, - sortedRaids: sortedRaids, - ...(await serverSideTranslations(locale, ['common', 'roadmap'])), - // Will be passed to the page component as props - }, + return { + props: { + user: user, + teams: teams, + meta: meta, + raids: raids, + sortedRaids: sortedRaids, + ...(await serverSideTranslations(locale, ['common', 'roadmap'])), + // Will be passed to the page component as props + }, + } + } catch (error) { + printError(error, 'axios') } } diff --git a/pages/new/index.tsx b/pages/new/index.tsx index d3f3881b..3464fe50 100644 --- a/pages/new/index.tsx +++ b/pages/new/index.tsx @@ -5,11 +5,12 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import Party from '~components/Party' -import { appState } from '~utils/appState' -import { groupWeaponKeys } from '~utils/groupWeaponKeys' +import api from '~utils/api' import organizeRaids from '~utils/organizeRaids' import setUserToken from '~utils/setUserToken' -import api from '~utils/api' +import { appState } from '~utils/appState' +import { groupWeaponKeys } from '~utils/groupWeaponKeys' +import { printError } from '~utils/reportError' import type { NextApiRequest, NextApiResponse } from 'next' import type { GroupedWeaponKeys } from '~utils/groupWeaponKeys' @@ -82,32 +83,34 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex // Set headers for server-side requests setUserToken(req, res) - let { raids, sortedRaids } = await api.endpoints.raids - .getAll() - .then((response) => organizeRaids(response.data)) + try { + let { raids, sortedRaids } = await api.endpoints.raids + .getAll() + .then((response) => organizeRaids(response.data)) - let jobs = await api.endpoints.jobs - .getAll() - .then((response) => { + let jobs = await api.endpoints.jobs.getAll().then((response) => { return response.data }) - let jobSkills = await api.allJobSkills().then((response) => response.data) + let jobSkills = await api.allJobSkills().then((response) => response.data) - let weaponKeys = await api.endpoints.weapon_keys - .getAll() - .then((response) => groupWeaponKeys(response.data)) + let weaponKeys = await api.endpoints.weapon_keys + .getAll() + .then((response) => groupWeaponKeys(response.data)) - return { - props: { - jobs: jobs, - jobSkills: jobSkills, - raids: raids, - sortedRaids: sortedRaids, - weaponKeys: weaponKeys, - ...(await serverSideTranslations(locale, ['common', 'roadmap'])), - // Will be passed to the page component as props - }, + return { + props: { + jobs: jobs, + jobSkills: jobSkills, + raids: raids, + sortedRaids: sortedRaids, + weaponKeys: weaponKeys, + ...(await serverSideTranslations(locale, ['common', 'roadmap'])), + // Will be passed to the page component as props + }, + } + } catch (error) { + printError(error, 'axios') } } diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index c015abea..58fe689c 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -6,17 +6,17 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import Party from '~components/Party' -import { appState } from '~utils/appState' -import { groupWeaponKeys } from '~utils/groupWeaponKeys' +import api from '~utils/api' import generateTitle from '~utils/generateTitle' import organizeRaids from '~utils/organizeRaids' import setUserToken from '~utils/setUserToken' -import api from '~utils/api' +import { appState } from '~utils/appState' +import { groupWeaponKeys } from '~utils/groupWeaponKeys' import { GridType } from '~utils/enums' +import { printError } from '~utils/reportError' import type { NextApiRequest, NextApiResponse } from 'next' import type { GroupedWeaponKeys } from '~utils/groupWeaponKeys' -import { useQueryState } from 'next-usequerystate' interface Props { party: Party @@ -154,74 +154,74 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex // Set headers for server-side requests setUserToken(req, res) - let { raids, sortedRaids } = await api.endpoints.raids - .getAll() - .then((response) => organizeRaids(response.data)) + try { + let { raids, sortedRaids } = await api.endpoints.raids + .getAll() + .then((response) => organizeRaids(response.data)) - let jobs = await api.endpoints.jobs - .getAll() - .then((response) => { + let jobs = await api.endpoints.jobs.getAll().then((response) => { return response.data }) - let jobSkills = await api - .allJobSkills() - .then((response) => response.data) + let jobSkills = await api.allJobSkills().then((response) => response.data) - let weaponKeys = await api.endpoints.weapon_keys - .getAll() - .then((response) => groupWeaponKeys(response.data)) + let weaponKeys = await api.endpoints.weapon_keys + .getAll() + .then((response) => groupWeaponKeys(response.data)) - let party: Party | null = null - if (query.party) { - let response = await api.endpoints.parties.getOne({ - id: query.party - }) - party = response.data.party - } else { - console.log('No party code') - } - - function getElement() { - if (party) { - const mainhand = party.weapons.find((weapon) => weapon.mainhand) - if (mainhand && mainhand.object.element === 0) { - return mainhand.element - } else { - return mainhand?.object.element - } + let party: Party | null = null + if (query.party) { + let response = await api.endpoints.parties.getOne({ + id: query.party, + }) + party = response.data.party } else { - return 0 + console.log('No party code') } - } - function elementEmoji() { - const element = getElement() + function getElement() { + if (party) { + const mainhand = party.weapons.find((weapon) => weapon.mainhand) + if (mainhand && mainhand.object.element === 0) { + return mainhand.element + } else { + return mainhand?.object.element + } + } else { + return 0 + } + } - if (element === 0) return '⚪' - else if (element === 1) return '🟢' - else if (element === 2) return '🔴' - else if (element === 3) return '🔵' - else if (element === 4) return '🟤' - else if (element === 5) return '🟣' - else if (element === 6) return '🟡' - else return '⚪' - } + function elementEmoji() { + const element = getElement() - return { - props: { - party: party, - jobs: jobs, - jobSkills: jobSkills, - raids: raids, - sortedRaids: sortedRaids, - weaponKeys: weaponKeys, - meta: { - element: elementEmoji(), + if (element === 0) return '⚪' + else if (element === 1) return '🟢' + else if (element === 2) return '🔴' + else if (element === 3) return '🔵' + else if (element === 4) return '🟤' + else if (element === 5) return '🟣' + else if (element === 6) return '🟡' + else return '⚪' + } + + return { + props: { + party: party, + jobs: jobs, + jobSkills: jobSkills, + raids: raids, + sortedRaids: sortedRaids, + weaponKeys: weaponKeys, + meta: { + element: elementEmoji(), + }, + ...(await serverSideTranslations(locale, ['common', 'roadmap'])), + // Will be passed to the page component as props }, - ...(await serverSideTranslations(locale, ['common', 'roadmap'])), - // Will be passed to the page component as props - }, + } + } catch (error) { + printError(error, 'axios') } } diff --git a/pages/saved.tsx b/pages/saved.tsx index b6bd1aba..546c1c09 100644 --- a/pages/saved.tsx +++ b/pages/saved.tsx @@ -16,6 +16,7 @@ import organizeRaids from '~utils/organizeRaids' import useDidMountEffect from '~utils/useDidMountEffect' import { elements, allElement } from '~data/elements' import { emptyPaginationObject } from '~utils/emptyStates' +import { printError } from '~utils/reportError' import GridRep from '~components/GridRep' import GridRepCollection from '~components/GridRepCollection' @@ -352,39 +353,43 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex // Set headers for server-side requests setUserToken(req, res) - // Fetch and organize raids - let { raids, sortedRaids } = await api.endpoints.raids - .getAll() - .then((response) => organizeRaids(response.data)) + try { + // Fetch and organize raids + let { raids, sortedRaids } = await api.endpoints.raids + .getAll() + .then((response) => organizeRaids(response.data)) - // Create filter object - const filters: FilterObject = extractFilters(query, raids) - const params = { - params: { ...filters }, - } + // Create filter object + const filters: FilterObject = extractFilters(query, raids) + const params = { + params: { ...filters }, + } - // Set up empty variables - let teams: Party[] | null = null - let meta: PaginationObject = emptyPaginationObject + // Set up empty variables + let teams: Party[] | null = null + let meta: PaginationObject = emptyPaginationObject - // Fetch initial set of saved parties - const response = await api.savedTeams(params) + // Fetch initial set of saved parties + const response = await api.savedTeams(params) - // Assign values to pass to props - teams = response.data.results - meta.count = response.data.meta.count - meta.totalPages = response.data.meta.total_pages - meta.perPage = response.data.meta.per_page + // Assign values to pass to props + teams = response.data.results + meta.count = response.data.meta.count + meta.totalPages = response.data.meta.total_pages + meta.perPage = response.data.meta.per_page - return { - props: { - teams: teams, - meta: meta, - raids: raids, - sortedRaids: sortedRaids, - ...(await serverSideTranslations(locale, ['common', 'roadmap'])), - // Will be passed to the page component as props - }, + return { + props: { + teams: teams, + meta: meta, + raids: raids, + sortedRaids: sortedRaids, + ...(await serverSideTranslations(locale, ['common', 'roadmap'])), + // Will be passed to the page component as props + }, + } + } catch (error) { + printError(error, 'axios') } } diff --git a/pages/teams.tsx b/pages/teams.tsx index 03502514..a27da820 100644 --- a/pages/teams.tsx +++ b/pages/teams.tsx @@ -16,6 +16,7 @@ import organizeRaids from '~utils/organizeRaids' import useDidMountEffect from '~utils/useDidMountEffect' import { elements, allElement } from '~data/elements' import { emptyPaginationObject } from '~utils/emptyStates' +import { printError } from '~utils/reportError' import GridRep from '~components/GridRep' import GridRepCollection from '~components/GridRepCollection' @@ -364,38 +365,42 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex setUserToken(req, res) // Fetch and organize raids - let { raids, sortedRaids } = await api.endpoints.raids - .getAll() - .then((response) => organizeRaids(response.data)) + try { + let { raids, sortedRaids } = await api.endpoints.raids + .getAll() + .then((response) => organizeRaids(response.data)) - // Create filter object - const filters: FilterObject = extractFilters(query, raids) - const params = { - params: { ...filters }, - } + // Create filter object + const filters: FilterObject = extractFilters(query, raids) + const params = { + params: { ...filters }, + } - // Set up empty variables - let teams: Party[] | null = null - let meta: PaginationObject = emptyPaginationObject + // Set up empty variables + let teams: Party[] | null = null + let meta: PaginationObject = emptyPaginationObject - // Fetch initial set of parties - const response = await api.endpoints.parties.getAll(params) + // Fetch initial set of parties + const response = await api.endpoints.parties.getAll(params) - // Assign values to pass to props - teams = response.data.results - meta.count = response.data.meta.count - meta.totalPages = response.data.meta.total_pages - meta.perPage = response.data.meta.per_page + // Assign values to pass to props + teams = response.data.results + meta.count = response.data.meta.count + meta.totalPages = response.data.meta.total_pages + meta.perPage = response.data.meta.per_page - return { - props: { - teams: teams, - meta: meta, - raids: raids, - sortedRaids: sortedRaids, - ...(await serverSideTranslations(locale, ['common', 'roadmap'])), - // Will be passed to the page component as props - }, + return { + props: { + teams: teams, + meta: meta, + raids: raids, + sortedRaids: sortedRaids, + ...(await serverSideTranslations(locale, ['common', 'roadmap'])), + // Will be passed to the page component as props + }, + } + } catch (error) { + printError(error, 'axios') } } diff --git a/utils/reportError.tsx b/utils/reportError.tsx new file mode 100644 index 00000000..d24d6008 --- /dev/null +++ b/utils/reportError.tsx @@ -0,0 +1,20 @@ +import { AxiosError } from 'axios' + +function handleError(error: any) { + if (error instanceof Error) return error.message +} + +function handleAxiosError(error: any) { + const axiosError = error as AxiosError + return axiosError.response +} + +export function printError(error: any, type?: string) { + if (type === 'axios') { + const response = handleAxiosError(error) + console.log(`${response?.status} ${response?.statusText}`) + console.log(response?.data.toJSON()) + } else { + console.log(handleError(error)) + } +} From 82f1bef0dc37b26dfc22735effbe0acefc7ed3d7 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 14:47:31 -0800 Subject: [PATCH 03/89] Fix build error --- pages/p/[party].tsx | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index 58fe689c..8ae2af4a 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -154,6 +154,32 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex // Set headers for server-side requests setUserToken(req, res) + function getElement(party?: Party) { + if (party) { + const mainhand = party.weapons.find((weapon) => weapon.mainhand) + if (mainhand && mainhand.object.element === 0) { + return mainhand.element + } else { + return mainhand?.object.element + } + } else { + return 0 + } + } + + function elementEmoji(party?: Party) { + const element = getElement(party) + + if (element === 0) return '⚪' + else if (element === 1) return '🟢' + else if (element === 2) return '🔴' + else if (element === 3) return '🔵' + else if (element === 4) return '🟤' + else if (element === 5) return '🟣' + else if (element === 6) return '🟡' + else return '⚪' + } + try { let { raids, sortedRaids } = await api.endpoints.raids .getAll() @@ -169,7 +195,7 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex .getAll() .then((response) => groupWeaponKeys(response.data)) - let party: Party | null = null + let party: Party | undefined = undefined if (query.party) { let response = await api.endpoints.parties.getOne({ id: query.party, @@ -179,32 +205,6 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex console.log('No party code') } - function getElement() { - if (party) { - const mainhand = party.weapons.find((weapon) => weapon.mainhand) - if (mainhand && mainhand.object.element === 0) { - return mainhand.element - } else { - return mainhand?.object.element - } - } else { - return 0 - } - } - - function elementEmoji() { - const element = getElement() - - if (element === 0) return '⚪' - else if (element === 1) return '🟢' - else if (element === 2) return '🔴' - else if (element === 3) return '🔵' - else if (element === 4) return '🟤' - else if (element === 5) return '🟣' - else if (element === 6) return '🟡' - else return '⚪' - } - return { props: { party: party, @@ -214,7 +214,7 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex sortedRaids: sortedRaids, weaponKeys: weaponKeys, meta: { - element: elementEmoji(), + element: elementEmoji(party), }, ...(await serverSideTranslations(locale, ['common', 'roadmap'])), // Will be passed to the page component as props From a4cc331f5ebb1e8b29b17a9aa1729301d608d8d2 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 15:09:34 -0800 Subject: [PATCH 04/89] Use proper URL for job icons Before we were linking to local icons, but these will live on S3 --- components/JobDropdown/index.tsx | 6 ++++-- components/JobSection/index.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/JobDropdown/index.tsx b/components/JobDropdown/index.tsx index 71fc6eee..7d4b0ab7 100644 --- a/components/JobDropdown/index.tsx +++ b/components/JobDropdown/index.tsx @@ -95,7 +95,7 @@ const JobDropdown = React.forwardRef( key={i} value={item.id} altText={item.name[locale]} - iconSrc={`/images/job-icons/${item.granblue_id}.png`} + iconSrc={`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/job-icons/${item.granblue_id}.png`} > {item.name[locale]} @@ -116,7 +116,9 @@ const JobDropdown = React.forwardRef( value={currentJob ? currentJob.id : 'no-job'} altText={currentJob ? currentJob.name[locale] : ''} iconSrc={ - currentJob ? `/images/job-icons/${currentJob.granblue_id}.png` : '' + currentJob + ? `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/job-icons/${currentJob.granblue_id}.png` + : '' } open={open} onClick={openJobSelect} diff --git a/components/JobSection/index.tsx b/components/JobSection/index.tsx index 8411cfbb..2cc274a1 100644 --- a/components/JobSection/index.tsx +++ b/components/JobSection/index.tsx @@ -149,7 +149,7 @@ const JobSection = (props: Props) => {
{party.job.name[locale]}

{party.job ? party.job.name[locale] : t('no_job')}

From 13d15c9eb8dc8d69910084d5ca26e96f4a485645 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 22:08:17 -0800 Subject: [PATCH 05/89] Added api endpoint --- utils/api.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/api.tsx b/utils/api.tsx index 352f60ed..148df604 100644 --- a/utils/api.tsx +++ b/utils/api.tsx @@ -115,6 +115,11 @@ class Api { return axios.get(resourceUrl, params) } + jobAccessoriesForJob(jobId: string, params?: {}) { + const resourceUrl = `${this.url}/jobs/${jobId}/accessories` + return axios.get(resourceUrl, params) + } + savedTeams(params: {}) { const resourceUrl = `${this.url}/parties/favorites` return axios.get(resourceUrl, params) From fadf422d9afe26705359dbb358c0c851e5fa3ce4 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 22:08:23 -0800 Subject: [PATCH 06/89] Added shield asset --- public/icons/Shield.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 public/icons/Shield.svg diff --git a/public/icons/Shield.svg b/public/icons/Shield.svg new file mode 100644 index 00000000..35fe26d8 --- /dev/null +++ b/public/icons/Shield.svg @@ -0,0 +1,3 @@ + + + From 6f32c975ce92725742b74b6cb2cbafcb4282f30c Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 23 Jan 2023 22:08:38 -0800 Subject: [PATCH 07/89] Extracted display of Job image into a component --- components/JobImage/index.scss | 80 ++++++++++++++++++++++++++++++++ components/JobImage/index.tsx | 61 ++++++++++++++++++++++++ components/JobSection/index.scss | 57 ----------------------- components/JobSection/index.tsx | 14 +++--- 4 files changed, 147 insertions(+), 65 deletions(-) create mode 100644 components/JobImage/index.scss create mode 100644 components/JobImage/index.tsx diff --git a/components/JobImage/index.scss b/components/JobImage/index.scss new file mode 100644 index 00000000..a5004f66 --- /dev/null +++ b/components/JobImage/index.scss @@ -0,0 +1,80 @@ +.JobImage { + $height: 252px; + $width: 447px; + + aspect-ratio: 7/9; + background: url('/images/background_a.jpg'); + background-size: 500px 281px; + border-radius: $unit; + box-sizing: border-box; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); + display: block; + isolation: isolate; + flex-grow: 2; + flex-shrink: 0; + height: $height; + margin-right: $unit * 3; + max-height: $height; + max-width: $width; + overflow: hidden; + position: relative; + width: $width; + transition: box-shadow 0.15s ease-in-out; + + // prettier-ignore + @media only screen + and (max-width: 800px) + and (max-height: 920px) + and (-webkit-min-device-pixel-ratio: 2) { + margin-right: 0; + width: 100%; + } + + @include breakpoint(phone) { + aspect-ratio: 16/9; + margin: 0; + width: 100%; + height: inherit; + } + + img { + -webkit-filter: drop-shadow(4px 4px 8px rgba(0, 0, 0, 0.48)); + filter: drop-shadow(4px 4px 8px rgba(0, 0, 0, 0.48)); + position: relative; + top: $unit * -4; + left: 50%; + transform: translateX(-50%); + width: 100%; + z-index: 2; + } + + .JobAccessory.Button { + align-items: center; + border-radius: 99px; + justify-content: center; + position: relative; + padding: $unit * 1.5; + top: $unit; + left: $unit; + height: auto; + z-index: 10; + + &:hover .Accessory svg { + stroke: var(--button-text-hover); + } + + .Accessory svg { + fill: none; + stroke: var(--button-text); + stroke-width: 3px; + width: $unit-3x; + height: auto; + } + } + + .Overlay { + background: none; + position: absolute; + z-index: 1; + } +} diff --git a/components/JobImage/index.tsx b/components/JobImage/index.tsx new file mode 100644 index 00000000..d7000292 --- /dev/null +++ b/components/JobImage/index.tsx @@ -0,0 +1,61 @@ +import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + +import Button from '~components/Button' +import ShieldIcon from '~public/icons/Shield.svg' +import './index.scss' + +interface Props { + job?: Job + user?: User + onAccessoryButtonClicked: () => void +} + +const ACCESSORY_JOB_IDS = ['683ffee8-4ea2-432d-bc30-4865020ac9f4'] + +const JobImage = ({ job, user, onAccessoryButtonClicked }: Props) => { + // Localization + const { t } = useTranslation('common') + + const router = useRouter() + const locale = + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' + + // Static variables + const imageUrl = () => { + let source = '' + + if (job) { + const slug = job.name.en.replaceAll(' ', '-').toLowerCase() + const gender = user && user.gender == 1 ? 'b' : 'a' + source = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/jobs/${slug}_${gender}.png` + } + + return source + } + + const hasAccessory = job && ACCESSORY_JOB_IDS.includes(job.id) + const image = {job?.name[locale]} + + // Elements + const accessoryButton = () => { + return ( + ) }) diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index d813b877..6e1b0674 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -218,7 +218,7 @@ const CharacterUnit = ({