Merge pull request #32 from jedmund/class
Add support for selecting Jobs for teams
This commit is contained in:
commit
4ae8f829df
22 changed files with 390 additions and 23 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -50,6 +50,7 @@ dist/
|
||||||
public/images/weapon*
|
public/images/weapon*
|
||||||
public/images/summon*
|
public/images/summon*
|
||||||
public/images/chara*
|
public/images/chara*
|
||||||
|
public/images/jobs
|
||||||
|
|
||||||
# Typescript v1 declaration files
|
# Typescript v1 declaration files
|
||||||
typings/
|
typings/
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,19 @@ const AccountModal = () => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [picture, setPicture] = useState('')
|
const [picture, setPicture] = useState('')
|
||||||
const [language, setLanguage] = useState('')
|
const [language, setLanguage] = useState('')
|
||||||
|
const [gender, setGender] = useState(0)
|
||||||
const [privateProfile, setPrivateProfile] = useState(false)
|
const [privateProfile, setPrivateProfile] = useState(false)
|
||||||
|
|
||||||
// Refs
|
// Refs
|
||||||
const pictureSelect = React.createRef<HTMLSelectElement>()
|
const pictureSelect = React.createRef<HTMLSelectElement>()
|
||||||
const languageSelect = React.createRef<HTMLSelectElement>()
|
const languageSelect = React.createRef<HTMLSelectElement>()
|
||||||
|
const genderSelect = React.createRef<HTMLSelectElement>()
|
||||||
const privateSelect = React.createRef<HTMLInputElement>()
|
const privateSelect = React.createRef<HTMLInputElement>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cookies.user) setPicture(cookies.user.picture)
|
if (cookies.user) setPicture(cookies.user.picture)
|
||||||
if (cookies.user) setLanguage(cookies.user.language)
|
if (cookies.user) setLanguage(cookies.user.language)
|
||||||
|
if (cookies.user) setGender(cookies.user.gender)
|
||||||
}, [cookies])
|
}, [cookies])
|
||||||
|
|
||||||
const pictureOptions = (
|
const pictureOptions = (
|
||||||
|
|
@ -66,6 +69,11 @@ const AccountModal = () => {
|
||||||
setLanguage(languageSelect.current.value)
|
setLanguage(languageSelect.current.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleGenderChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
|
if (genderSelect.current)
|
||||||
|
setGender(parseInt(genderSelect.current.value))
|
||||||
|
}
|
||||||
|
|
||||||
function handlePrivateChange(checked: boolean) {
|
function handlePrivateChange(checked: boolean) {
|
||||||
setPrivateProfile(checked)
|
setPrivateProfile(checked)
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +86,7 @@ const AccountModal = () => {
|
||||||
picture: picture,
|
picture: picture,
|
||||||
element: pictureData.find(i => i.filename === picture)?.element,
|
element: pictureData.find(i => i.filename === picture)?.element,
|
||||||
language: language,
|
language: language,
|
||||||
|
gender: gender,
|
||||||
private: privateProfile
|
private: privateProfile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +98,8 @@ const AccountModal = () => {
|
||||||
const cookieObj = {
|
const cookieObj = {
|
||||||
picture: user.picture.picture,
|
picture: user.picture.picture,
|
||||||
element: user.picture.element,
|
element: user.picture.element,
|
||||||
language: user.language,
|
gender: user.gender,
|
||||||
|
language: user.language
|
||||||
}
|
}
|
||||||
|
|
||||||
setCookies('user', cookieObj, { path: '/'})
|
setCookies('user', cookieObj, { path: '/'})
|
||||||
|
|
@ -98,7 +108,8 @@ const AccountModal = () => {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
picture: user.picture.picture,
|
picture: user.picture.picture,
|
||||||
element: user.picture.element
|
element: user.picture.element,
|
||||||
|
gender: user.gender
|
||||||
}
|
}
|
||||||
|
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -157,6 +168,16 @@ const AccountModal = () => {
|
||||||
{pictureOptions}
|
{pictureOptions}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="field">
|
||||||
|
<div className="left">
|
||||||
|
<label>{t('modals.settings.labels.gender')}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<select name="gender" onChange={handleGenderChange} value={gender} ref={genderSelect}>
|
||||||
|
<option key="gran" value="0">{t('modals.settings.gender.gran')}</option>
|
||||||
|
<option key="djeeta" value="1">{t('modals.settings.gender.djeeta')}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<div className="left">
|
<div className="left">
|
||||||
<label>{t('modals.settings.labels.language')}</label>
|
<label>{t('modals.settings.labels.language')}</label>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#CharacterGrid {
|
#CharacterGrid {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
margin: auto;
|
||||||
|
max-width: 761px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#grid_characters {
|
#grid_characters {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { useSnapshot } from 'valtio'
|
||||||
import { AxiosResponse } from 'axios'
|
import { AxiosResponse } from 'axios'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
|
import JobSection from '~components/JobSection'
|
||||||
import CharacterUnit from '~components/CharacterUnit'
|
import CharacterUnit from '~components/CharacterUnit'
|
||||||
|
|
||||||
import api from '~utils/api'
|
import api from '~utils/api'
|
||||||
|
|
@ -227,22 +228,25 @@ const CharacterGrid = (props: Props) => {
|
||||||
|
|
||||||
// Render: JSX components
|
// Render: JSX components
|
||||||
return (
|
return (
|
||||||
<div id="CharacterGrid">
|
<div>
|
||||||
<ul id="grid_characters">
|
<div id="CharacterGrid">
|
||||||
{Array.from(Array(numCharacters)).map((x, i) => {
|
<JobSection />
|
||||||
return (
|
<ul id="grid_characters">
|
||||||
<li key={`grid_unit_${i}`} >
|
{Array.from(Array(numCharacters)).map((x, i) => {
|
||||||
<CharacterUnit
|
return (
|
||||||
gridCharacter={grid.characters[i]}
|
<li key={`grid_unit_${i}`} >
|
||||||
editable={party.editable}
|
<CharacterUnit
|
||||||
position={i}
|
gridCharacter={grid.characters[i]}
|
||||||
updateObject={receiveCharacterFromSearch}
|
editable={party.editable}
|
||||||
updateUncap={initiateUncapUpdate}
|
position={i}
|
||||||
/>
|
updateObject={receiveCharacterFromSearch}
|
||||||
</li>
|
updateUncap={initiateUncapUpdate}
|
||||||
)
|
/>
|
||||||
})}
|
</li>
|
||||||
</ul>
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
0
components/JobDropdown/index.scss
Normal file
0
components/JobDropdown/index.scss
Normal file
97
components/JobDropdown/index.tsx
Normal file
97
components/JobDropdown/index.tsx
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
import api from '~utils/api'
|
||||||
|
import { appState } from '~utils/appState'
|
||||||
|
import { jobGroups } from '~utils/jobGroups'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
currentJob?: string
|
||||||
|
onChange?: (job?: Job) => void
|
||||||
|
onBlur?: (event: React.ChangeEvent<HTMLSelectElement>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupedJob = { [key: string]: Job[] }
|
||||||
|
|
||||||
|
const JobDropdown = React.forwardRef<HTMLSelectElement, Props>(function useFieldSet(props, ref) {
|
||||||
|
// Set up router for locale
|
||||||
|
const router = useRouter()
|
||||||
|
const locale = router.locale || 'en'
|
||||||
|
|
||||||
|
// Set up local states for storing jobs
|
||||||
|
const [currentJob, setCurrentJob] = useState<Job>()
|
||||||
|
const [jobs, setJobs] = useState<Job[]>()
|
||||||
|
const [sortedJobs, setSortedJobs] = useState<GroupedJob>()
|
||||||
|
|
||||||
|
// Organize jobs into groups on mount
|
||||||
|
const organizeJobs = useCallback((jobs: Job[]) => {
|
||||||
|
const jobGroups = jobs.map(job => job.row).filter((value, index, self) => self.indexOf(value) === index)
|
||||||
|
let groupedJobs: GroupedJob = {}
|
||||||
|
|
||||||
|
jobGroups.forEach(group => {
|
||||||
|
groupedJobs[group] = jobs.filter(job => job.row === group)
|
||||||
|
})
|
||||||
|
|
||||||
|
setJobs(jobs)
|
||||||
|
setSortedJobs(groupedJobs)
|
||||||
|
appState.jobs = jobs
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Fetch all jobs on mount
|
||||||
|
useEffect(() => {
|
||||||
|
api.endpoints.jobs.getAll()
|
||||||
|
.then(response => organizeJobs(response.data))
|
||||||
|
}, [organizeJobs])
|
||||||
|
|
||||||
|
// Set current job on mount
|
||||||
|
useEffect(() => {
|
||||||
|
if (jobs && props.currentJob) {
|
||||||
|
const job = jobs.find(job => job.id === props.currentJob)
|
||||||
|
setCurrentJob(job)
|
||||||
|
}
|
||||||
|
}, [jobs, props.currentJob])
|
||||||
|
|
||||||
|
// Enable changing select value
|
||||||
|
function handleChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
|
if (jobs) {
|
||||||
|
const job = jobs.find(job => job.id === event.target.value)
|
||||||
|
if (props.onChange) props.onChange(job)
|
||||||
|
setCurrentJob(job)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render JSX for each job option, sorted into optgroups
|
||||||
|
function renderJobGroup(group: string) {
|
||||||
|
const options = sortedJobs && sortedJobs[group].length > 0 &&
|
||||||
|
sortedJobs[group].sort((a, b) => a.order - b.order).map((item, i) => {
|
||||||
|
return (
|
||||||
|
<option key={i} value={item.id}>{item.name[locale]}</option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const groupName = jobGroups.find(g => g.slug === group)?.name[locale]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<optgroup key={group} label={groupName}>
|
||||||
|
{options}
|
||||||
|
</optgroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
key={currentJob?.id}
|
||||||
|
value={currentJob?.id}
|
||||||
|
onBlur={props.onBlur}
|
||||||
|
onChange={handleChange}
|
||||||
|
ref={ref}>
|
||||||
|
<option key="no-job" value={-1}>No class</option>
|
||||||
|
{ (sortedJobs) ? Object.keys(sortedJobs).map(x => renderJobGroup(x)) : '' }
|
||||||
|
</select>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default JobDropdown
|
||||||
44
components/JobSection/index.scss
Normal file
44
components/JobSection/index.scss
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#Job {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: $unit * 3;
|
||||||
|
|
||||||
|
select {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.JobImage {
|
||||||
|
$height: 249px;
|
||||||
|
$width: 447px;
|
||||||
|
|
||||||
|
background: url('/images/background_a.jpg');
|
||||||
|
background-size: 500px 281px;
|
||||||
|
border-radius: $unit;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
|
||||||
|
display: block;
|
||||||
|
flex-grow: 2;
|
||||||
|
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;
|
||||||
|
|
||||||
|
img {
|
||||||
|
position: relative;
|
||||||
|
top: $unit * -4;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Overlay {
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
components/JobSection/index.tsx
Normal file
64
components/JobSection/index.tsx
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useSnapshot } from 'valtio'
|
||||||
|
|
||||||
|
import JobDropdown from '~components/JobDropdown'
|
||||||
|
|
||||||
|
import { appState } from '~utils/appState'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {}
|
||||||
|
|
||||||
|
const JobSection = (props: Props) => {
|
||||||
|
const [job, setJob] = useState<Job>()
|
||||||
|
const [imageUrl, setImageUrl] = useState('')
|
||||||
|
|
||||||
|
const { party } = useSnapshot(appState)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Set current job based on ID
|
||||||
|
setJob(party.job)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
generateImageUrl()
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (job) appState.party.job = job
|
||||||
|
}, [job])
|
||||||
|
|
||||||
|
function receiveJob(job?: Job) {
|
||||||
|
setJob(job)
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateImageUrl() {
|
||||||
|
let imgSrc = ""
|
||||||
|
|
||||||
|
if (job) {
|
||||||
|
const slug = job?.name.en.replaceAll(' ', '-').toLowerCase()
|
||||||
|
const gender = (party.user && party.user.gender == 1) ? 'b' : 'a'
|
||||||
|
|
||||||
|
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/jobs/${slug}_${gender}.png`
|
||||||
|
}
|
||||||
|
|
||||||
|
setImageUrl(imgSrc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render: JSX components
|
||||||
|
return (
|
||||||
|
<section id="Job">
|
||||||
|
<div className="JobImage">
|
||||||
|
<img src={imageUrl} />
|
||||||
|
<div className="Overlay" />
|
||||||
|
</div>
|
||||||
|
<JobDropdown
|
||||||
|
currentJob={ (party.job) ? party.job.id : undefined}
|
||||||
|
onChange={receiveJob}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JobSection
|
||||||
|
|
@ -132,6 +132,7 @@ const LoginModal = (props: Props) => {
|
||||||
picture: user.picture.picture,
|
picture: user.picture.picture,
|
||||||
element: user.picture.element,
|
element: user.picture.element,
|
||||||
language: user.language,
|
language: user.language,
|
||||||
|
gender: user.gender
|
||||||
}
|
}
|
||||||
|
|
||||||
setCookies('user', cookieObj, { path: '/' })
|
setCookies('user', cookieObj, { path: '/' })
|
||||||
|
|
@ -140,7 +141,8 @@ const LoginModal = (props: Props) => {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
picture: user.picture.picture,
|
picture: user.picture.picture,
|
||||||
element: user.picture.element
|
element: user.picture.element,
|
||||||
|
gender: user.gender
|
||||||
}
|
}
|
||||||
|
|
||||||
accountState.account.authorized = true
|
accountState.account.authorized = true
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { useRouter } from 'next/router'
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { useCookies } from 'react-cookie'
|
import { useCookies } from 'react-cookie'
|
||||||
import clonedeep from 'lodash.clonedeep'
|
import clonedeep from 'lodash.clonedeep'
|
||||||
|
import { subscribeKey } from 'valtio/utils'
|
||||||
|
|
||||||
import PartySegmentedControl from '~components/PartySegmentedControl'
|
import PartySegmentedControl from '~components/PartySegmentedControl'
|
||||||
import PartyDetails from '~components/PartyDetails'
|
import PartyDetails from '~components/PartyDetails'
|
||||||
|
|
@ -38,6 +39,9 @@ const Party = (props: Props) => {
|
||||||
|
|
||||||
// Set up states
|
// Set up states
|
||||||
const { party } = useSnapshot(appState)
|
const { party } = useSnapshot(appState)
|
||||||
|
const jobState = party.job
|
||||||
|
|
||||||
|
const [job, setJob] = useState<Job>()
|
||||||
const [currentTab, setCurrentTab] = useState<GridType>(GridType.Weapon)
|
const [currentTab, setCurrentTab] = useState<GridType>(GridType.Weapon)
|
||||||
|
|
||||||
// Reset state on first load
|
// Reset state on first load
|
||||||
|
|
@ -46,6 +50,14 @@ const Party = (props: Props) => {
|
||||||
appState.grid = resetState.grid
|
appState.grid = resetState.grid
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setJob(jobState)
|
||||||
|
}, [jobState])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
jobChanged()
|
||||||
|
}, [job])
|
||||||
|
|
||||||
// Methods: Creating a new party
|
// Methods: Creating a new party
|
||||||
async function createParty(extra: boolean = false) {
|
async function createParty(extra: boolean = false) {
|
||||||
let body = {
|
let body = {
|
||||||
|
|
@ -69,6 +81,14 @@ const Party = (props: Props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jobChanged() {
|
||||||
|
if (party.id) {
|
||||||
|
api.endpoints.parties.update(party.id, {
|
||||||
|
'party': { 'job_id': (job) ? job.id : '' }
|
||||||
|
}, headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateDetails(name?: string, description?: string, raid?: Raid) {
|
function updateDetails(name?: string, description?: string, raid?: Raid) {
|
||||||
if (appState.party.name !== name ||
|
if (appState.party.name !== name ||
|
||||||
appState.party.description !== description ||
|
appState.party.description !== description ||
|
||||||
|
|
@ -145,6 +165,7 @@ const Party = (props: Props) => {
|
||||||
appState.party.name = response.data.party.name
|
appState.party.name = response.data.party.name
|
||||||
appState.party.description = response.data.party.description
|
appState.party.description = response.data.party.description
|
||||||
appState.party.raid = response.data.party.raid
|
appState.party.raid = response.data.party.raid
|
||||||
|
appState.party.job = response.data.party.job
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleError = useCallback((error: any) => {
|
const handleError = useCallback((error: any) => {
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ const SignupModal = (props: Props) => {
|
||||||
picture: user.picture.picture,
|
picture: user.picture.picture,
|
||||||
element: user.picture.element,
|
element: user.picture.element,
|
||||||
language: user.language,
|
language: user.language,
|
||||||
|
gender: user.gender
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Set language
|
// TODO: Set language
|
||||||
|
|
@ -109,7 +110,8 @@ const SignupModal = (props: Props) => {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
picture: user.picture.picture,
|
picture: user.picture.picture,
|
||||||
element: user.picture.element
|
element: user.picture.element,
|
||||||
|
gender: user.gender
|
||||||
}
|
}
|
||||||
|
|
||||||
accountState.account.authorized = true
|
accountState.account.authorized = true
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ const emptyUser = {
|
||||||
picture: '',
|
picture: '',
|
||||||
element: ''
|
element: ''
|
||||||
},
|
},
|
||||||
private: false
|
private: false,
|
||||||
|
gender: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProfileRoute: React.FC = () => {
|
const ProfileRoute: React.FC = () => {
|
||||||
|
|
@ -123,7 +124,8 @@ const ProfileRoute: React.FC = () => {
|
||||||
username: response.data.user.username,
|
username: response.data.user.username,
|
||||||
granblueId: response.data.user.granblue_id,
|
granblueId: response.data.user.granblue_id,
|
||||||
picture: response.data.user.picture,
|
picture: response.data.user.picture,
|
||||||
private: response.data.user.private
|
private: response.data.user.private,
|
||||||
|
gender: response.data.user.gender
|
||||||
})
|
})
|
||||||
|
|
||||||
setTotalPages(response.data.parties.total_pages)
|
setTotalPages(response.data.parties.total_pages)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ function MyApp({ Component, pageProps }: AppProps) {
|
||||||
id: cookies.account.user_id,
|
id: cookies.account.user_id,
|
||||||
username: cookies.account.username,
|
username: cookies.account.username,
|
||||||
picture: '',
|
picture: '',
|
||||||
element: ''
|
element: '',
|
||||||
|
gender: 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`You are not currently logged in.`)
|
console.log(`You are not currently logged in.`)
|
||||||
|
|
|
||||||
BIN
public/images/background_a.jpg
Normal file
BIN
public/images/background_a.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 773 KiB |
|
|
@ -136,11 +136,16 @@
|
||||||
"labels": {
|
"labels": {
|
||||||
"picture": "Picture",
|
"picture": "Picture",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
|
"gender": "Main Character",
|
||||||
"private": "Private"
|
"private": "Private"
|
||||||
},
|
},
|
||||||
"descriptions": {
|
"descriptions": {
|
||||||
"private": "Hide your profile and prevent your grids from showing up in collections"
|
"private": "Hide your profile and prevent your grids from showing up in collections"
|
||||||
},
|
},
|
||||||
|
"gender": {
|
||||||
|
"gran": "Gran",
|
||||||
|
"djeeta": "Djeeta"
|
||||||
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"english": "English",
|
"english": "English",
|
||||||
"japanese": "Japanese"
|
"japanese": "Japanese"
|
||||||
|
|
|
||||||
|
|
@ -136,11 +136,16 @@
|
||||||
"labels": {
|
"labels": {
|
||||||
"picture": "プロフィール画像",
|
"picture": "プロフィール画像",
|
||||||
"language": "言語",
|
"language": "言語",
|
||||||
|
"gender": "主人公",
|
||||||
"private": "プライベート"
|
"private": "プライベート"
|
||||||
},
|
},
|
||||||
"descriptions": {
|
"descriptions": {
|
||||||
"private": "プロフィールを隠し、編成をコレクションに表示されないようにします"
|
"private": "プロフィールを隠し、編成をコレクションに表示されないようにします"
|
||||||
},
|
},
|
||||||
|
"gender": {
|
||||||
|
"gran": "グラン",
|
||||||
|
"djeeta": "ジータ"
|
||||||
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"english": "英語",
|
"english": "英語",
|
||||||
"japanese": "日本語"
|
"japanese": "日本語"
|
||||||
|
|
|
||||||
15
types/Job.d.ts
vendored
Normal file
15
types/Job.d.ts
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
interface Job {
|
||||||
|
id: string
|
||||||
|
row: string
|
||||||
|
ml: boolean
|
||||||
|
order: number
|
||||||
|
name: {
|
||||||
|
[key: string]: string
|
||||||
|
en: string
|
||||||
|
ja: string
|
||||||
|
}
|
||||||
|
proficiency: {
|
||||||
|
proficiency1: number
|
||||||
|
proficiency2: number
|
||||||
|
}
|
||||||
|
}
|
||||||
1
types/User.d.ts
vendored
1
types/User.d.ts
vendored
|
|
@ -6,5 +6,6 @@ interface User {
|
||||||
picture: string
|
picture: string
|
||||||
element: string
|
element: string
|
||||||
}
|
}
|
||||||
|
gender: number
|
||||||
private: boolean
|
private: boolean
|
||||||
}
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ interface AccountState {
|
||||||
username: string
|
username: string
|
||||||
picture: string
|
picture: string
|
||||||
element: string
|
element: string
|
||||||
|
gender: number
|
||||||
} | undefined
|
} | undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ api.createEntity( { name: 'grid_weapons' })
|
||||||
api.createEntity( { name: 'characters' })
|
api.createEntity( { name: 'characters' })
|
||||||
api.createEntity( { name: 'weapons' })
|
api.createEntity( { name: 'weapons' })
|
||||||
api.createEntity( { name: 'summons' })
|
api.createEntity( { name: 'summons' })
|
||||||
|
api.createEntity( { name: 'jobs' })
|
||||||
api.createEntity( { name: 'raids' })
|
api.createEntity( { name: 'raids' })
|
||||||
api.createEntity( { name: 'weapon_keys' })
|
api.createEntity( { name: 'weapon_keys' })
|
||||||
api.createEntity( { name: 'favorites' })
|
api.createEntity( { name: 'favorites' })
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,20 @@
|
||||||
import { proxy } from "valtio";
|
import { proxy } from "valtio";
|
||||||
|
|
||||||
|
const emptyJob: Job = {
|
||||||
|
id: "-1",
|
||||||
|
row: "",
|
||||||
|
ml: false,
|
||||||
|
order: 0,
|
||||||
|
name: {
|
||||||
|
en: "",
|
||||||
|
ja: ""
|
||||||
|
},
|
||||||
|
proficiency: {
|
||||||
|
proficiency1: 0,
|
||||||
|
proficiency2: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface AppState {
|
interface AppState {
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
|
|
||||||
|
|
@ -9,6 +24,7 @@ interface AppState {
|
||||||
detailsVisible: boolean,
|
detailsVisible: boolean,
|
||||||
name: string | undefined,
|
name: string | undefined,
|
||||||
description: string | undefined,
|
description: string | undefined,
|
||||||
|
job: Job,
|
||||||
raid: Raid | undefined,
|
raid: Raid | undefined,
|
||||||
element: number,
|
element: number,
|
||||||
extra: boolean,
|
extra: boolean,
|
||||||
|
|
@ -46,6 +62,7 @@ export const initialAppState: AppState = {
|
||||||
detailsVisible: false,
|
detailsVisible: false,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
description: undefined,
|
description: undefined,
|
||||||
|
job: emptyJob,
|
||||||
raid: undefined,
|
raid: undefined,
|
||||||
element: 0,
|
element: 0,
|
||||||
extra: false,
|
extra: false,
|
||||||
|
|
|
||||||
60
utils/jobGroups.tsx
Normal file
60
utils/jobGroups.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
interface JobGroup {
|
||||||
|
slug: string
|
||||||
|
name: {
|
||||||
|
[key: string]: string
|
||||||
|
en: string
|
||||||
|
ja: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const jobGroups: JobGroup[] = [
|
||||||
|
{
|
||||||
|
slug: "1",
|
||||||
|
name: {
|
||||||
|
en: 'Row I',
|
||||||
|
ja: 'Class I'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "2",
|
||||||
|
name: {
|
||||||
|
en: 'Row II',
|
||||||
|
ja: 'Class II'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "3",
|
||||||
|
name: {
|
||||||
|
en: 'Row III',
|
||||||
|
ja: 'Class III'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "4",
|
||||||
|
name: {
|
||||||
|
en: 'Row IV',
|
||||||
|
ja: 'Class IV'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "5",
|
||||||
|
name: {
|
||||||
|
en: 'Row V',
|
||||||
|
ja: 'Class V'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "ex1",
|
||||||
|
name: {
|
||||||
|
en: 'Extra I',
|
||||||
|
ja: 'EXTRA I'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "ex2",
|
||||||
|
name: {
|
||||||
|
en: 'Extra II',
|
||||||
|
ja: 'EXTRA II'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
Loading…
Reference in a new issue