mirror of
https://github.com/mgerb/classic-wow-forums
synced 2026-01-11 09:32:51 +00:00
client - user account page done
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { RouteComponentProps } from 'react-router-dom';
|
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import { Portrait } from '../portrait/portrait';
|
import { Portrait } from '../portrait/portrait';
|
||||||
import { UserStore } from '../../stores/user-store';
|
import { UserStore } from '../../stores/user-store';
|
||||||
|
import { CharacterService } from '../../services';
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<any> {
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
userStore?: UserStore;
|
userStore?: UserStore;
|
||||||
|
onNavigate: (des: string) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {}
|
interface State {}
|
||||||
@@ -26,9 +27,16 @@ export class LoginButton extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderPortrait() {
|
renderPortrait() {
|
||||||
|
const avatarSrc = CharacterService.getAvatar(this.props.userStore!.user!.character_avatar!);
|
||||||
return (
|
return (
|
||||||
<div onClick={() => this.props.history.push('/user-account')} style={{ cursor: 'pointer' }}>
|
<div style={{ padding: '10px' }}>
|
||||||
<Portrait imageSrc={require('../../assets/Tyren.gif')}/>
|
<div onClick={() => this.props.onNavigate('/user-account')} style={{ cursor: 'pointer' }}>
|
||||||
|
{avatarSrc && <Portrait imageSrc={avatarSrc}/>}
|
||||||
|
</div>
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
{!avatarSrc && <p><a onClick={() => this.props.onNavigate('/user-account')}>Account</a></p>}
|
||||||
|
<div><b>{this.props.userStore!.user!.character_name}</b></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,6 @@
|
|||||||
export interface AvatarModel {
|
export interface AvatarModel {
|
||||||
title: string;
|
|
||||||
imageSrc: any;
|
imageSrc: any;
|
||||||
|
raceId: number;
|
||||||
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AvatarList: AvatarModel[] = [
|
|
||||||
{
|
|
||||||
title: 'dwarf_f',
|
|
||||||
imageSrc: require('../assets/avatars/Dwarf_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'dwarf_m',
|
|
||||||
imageSrc: require('../assets/avatars/Dwarf_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'gnome_f',
|
|
||||||
imageSrc: require('../assets/avatars/Gnome_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'gnome_m',
|
|
||||||
imageSrc: require('../assets/avatars/Gnome_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'human_f',
|
|
||||||
imageSrc: require('../assets/avatars/Human_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'human_m',
|
|
||||||
imageSrc: require('../assets/avatars/Human_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'night_elf_f',
|
|
||||||
imageSrc: require('../assets/avatars/Night_elf_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'night_elf_m',
|
|
||||||
imageSrc: require('../assets/avatars/Night_elf_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'orc_f',
|
|
||||||
imageSrc: require('../assets/avatars/Orc_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'orc_m',
|
|
||||||
imageSrc: require('../assets/avatars/Orc_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'tauren_f',
|
|
||||||
imageSrc: require('../assets/avatars/Tauren_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'tauren_m',
|
|
||||||
imageSrc: require('../assets/avatars/Tauren_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'troll_f',
|
|
||||||
imageSrc: require('../assets/avatars/Troll_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'troll_m',
|
|
||||||
imageSrc: require('../assets/avatars/Troll_male.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'undead_f',
|
|
||||||
imageSrc: require('../assets/avatars/Undead_female.gif'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'undead_m',
|
|
||||||
imageSrc: require('../assets/avatars/Undead_male.gif'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { AvatarModel } from './avatar';
|
||||||
|
|
||||||
export interface CharacterModel {
|
export interface CharacterModel {
|
||||||
achievementPoints: number;
|
achievementPoints: number;
|
||||||
battlegroup: string;
|
battlegroup: string;
|
||||||
@@ -10,4 +12,7 @@ export interface CharacterModel {
|
|||||||
race: number;
|
race: number;
|
||||||
realm: string;
|
realm: string;
|
||||||
spec: any;
|
spec: any;
|
||||||
|
|
||||||
|
avatarList?: AvatarModel[];
|
||||||
|
races?: number[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export class Forum extends React.Component<Props, State> {
|
|||||||
<div className="forum-header">
|
<div className="forum-header">
|
||||||
<ForumNav />
|
<ForumNav />
|
||||||
<div style={{ height: '100%' }}>
|
<div style={{ height: '100%' }}>
|
||||||
<LoginButton {...this.props}/>
|
<LoginButton onNavigate={dest => this.props.history.push(dest)}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
transition: all 0.1s ease-in-out;
|
transition: all 0.1s ease-in-out;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
||||||
&:hover, &__selected {
|
&:hover, &--selected {
|
||||||
top: -1px;
|
top: -1px;
|
||||||
box-shadow: 0 0 10px #00C0FF;
|
box-shadow: 0 0 10px #00C0FF;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { RouteComponentProps } from 'react-router-dom';
|
|||||||
import { get, groupBy, map } from 'lodash';
|
import { get, groupBy, map } from 'lodash';
|
||||||
import { ContentContainer, Portrait, ScrollToTop } from '../../components';
|
import { ContentContainer, Portrait, ScrollToTop } from '../../components';
|
||||||
import { UserStore } from '../../stores/user-store';
|
import { UserStore } from '../../stores/user-store';
|
||||||
import { UserService } from '../../services';
|
import { CharacterService, UserService } from '../../services';
|
||||||
import { AvatarList, CharacterModel } from '../../model';
|
import { CharacterModel } from '../../model';
|
||||||
import './user-account.scss';
|
import './user-account.scss';
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<any> {
|
interface Props extends RouteComponentProps<any> {
|
||||||
@@ -16,6 +16,9 @@ interface State {
|
|||||||
characters: {[realm: string]: CharacterModel[]};
|
characters: {[realm: string]: CharacterModel[]};
|
||||||
selectedRealm?: string;
|
selectedRealm?: string;
|
||||||
selectedCharIndex: number;
|
selectedCharIndex: number;
|
||||||
|
selectedAvatarIndex: number;
|
||||||
|
insufficientScope?: boolean;
|
||||||
|
noCharacters: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@inject('userStore')
|
@inject('userStore')
|
||||||
@@ -25,7 +28,9 @@ export class UserAccount extends React.Component<Props, State> {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
characters: {},
|
characters: {},
|
||||||
|
noCharacters: false,
|
||||||
selectedCharIndex: 0,
|
selectedCharIndex: 0,
|
||||||
|
selectedAvatarIndex: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,22 +47,43 @@ export class UserAccount extends React.Component<Props, State> {
|
|||||||
async getCharacters() {
|
async getCharacters() {
|
||||||
try {
|
try {
|
||||||
const res = await UserService.getCharacters() as any;
|
const res = await UserService.getCharacters() as any;
|
||||||
const characters = groupBy(res, 'realm');
|
if (res.characters) {
|
||||||
this.setState({
|
if (res.characters.length === 0) {
|
||||||
characters,
|
this.setState({ noCharacters: true });
|
||||||
selectedRealm: res[0].realm,
|
return;
|
||||||
});
|
}
|
||||||
|
// remove classes that weren't in vanilla
|
||||||
|
const characters = groupBy(res.characters, 'realm');
|
||||||
|
this.setState({
|
||||||
|
characters,
|
||||||
|
selectedRealm: res.characters[0].realm,
|
||||||
|
insufficientScope: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({ insufficientScope: true });
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRealmSelect(event: any) {
|
onRealmSelect(event: any) {
|
||||||
this.setState({ selectedRealm: event.target.value, selectedCharIndex: 0 });
|
this.setState({
|
||||||
|
selectedRealm: event.target.value,
|
||||||
|
selectedCharIndex: 0,
|
||||||
|
selectedAvatarIndex: 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCharSelect(event: any) {
|
onCharSelect(event: any) {
|
||||||
this.setState({ selectedCharIndex: event.target.value as any });
|
this.setState({
|
||||||
|
selectedCharIndex: event.target.value as any,
|
||||||
|
selectedAvatarIndex: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onAvatarSelect(selectedAvatarIndex: number) {
|
||||||
|
this.setState({ selectedAvatarIndex });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDropDowns() {
|
renderDropDowns() {
|
||||||
@@ -65,24 +91,29 @@ export class UserAccount extends React.Component<Props, State> {
|
|||||||
return <div></div>;
|
return <div></div>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{ marginBottom: '10px' }}>
|
<div>
|
||||||
<select value={this.selectedCharacter().realm}
|
<h2>Set your default character</h2>
|
||||||
onChange={event => this.onRealmSelect(event)}>
|
<div style={{ margin: '0 10px 10px 0', display: 'inline-block' }}>
|
||||||
{map(this.state.characters, (_, realm: string) => {
|
<select value={this.selectedCharacter().realm}
|
||||||
return <option key={`realm${realm}`}>{realm}</option>;
|
onChange={event => this.onRealmSelect(event)}>
|
||||||
})}
|
{map(this.state.characters, (_, realm: string) => {
|
||||||
</select>
|
return <option key={`realm${realm}`}>{realm}</option>;
|
||||||
<select style={{ marginLeft: '5px' }}
|
})}
|
||||||
onChange={event => this.onCharSelect(event)}>
|
</select>
|
||||||
{map(this.state.characters[this.state.selectedRealm!], (value, index) => {
|
<select style={{ marginLeft: '5px' }}
|
||||||
return <option key={this.state.selectedRealm! + index} value={index}>{value.name}</option>;
|
onChange={event => this.onCharSelect(event)}>
|
||||||
})}
|
{map(this.state.characters[this.state.selectedRealm!], (value, index) => {
|
||||||
</select>
|
return <option key={this.state.selectedRealm! + index} value={index}>{value.name}</option>;
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a onClick={() => this.onSave()}>Save</a>
|
||||||
<div className="avatar-list">
|
<div className="avatar-list">
|
||||||
{AvatarList.map((val, index) => {
|
{this.selectedCharacter().avatarList!.map((val, index) => {
|
||||||
|
const avatarClass = this.state.selectedAvatarIndex === index ? 'avatar-list__item--selected' : '';
|
||||||
return (
|
return (
|
||||||
<div key={index} className="avatar-list__item">
|
<div key={index} className={`avatar-list__item ${avatarClass}`} onClick={() => this.onAvatarSelect(index)}>
|
||||||
<img src={val.imageSrc}/>
|
<img src={val.imageSrc}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -94,25 +125,61 @@ export class UserAccount extends React.Component<Props, State> {
|
|||||||
|
|
||||||
private async onSave() {
|
private async onSave() {
|
||||||
const { name, guild, realm } = this.selectedCharacter();
|
const { name, guild, realm } = this.selectedCharacter();
|
||||||
|
const selectedAvatar = this.selectedCharacter().avatarList![this.state.selectedAvatarIndex].title;
|
||||||
|
const charClass = CharacterService.getClass(this.selectedCharacter().class);
|
||||||
const data = {
|
const data = {
|
||||||
character_name: name,
|
character_name: name,
|
||||||
character_class: 'Rogue', // todo get class from number
|
character_class: charClass.name,
|
||||||
character_guild: guild,
|
character_guild: guild,
|
||||||
character_realm: realm,
|
character_realm: realm,
|
||||||
character_avatar: 'Avatar', // TODO:
|
character_avatar: selectedAvatar,
|
||||||
};
|
};
|
||||||
|
|
||||||
await UserService.saveCharacter(data);
|
await UserService.saveCharacter(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private logout() {
|
||||||
|
this.props.userStore!.resetUser();
|
||||||
|
window.location.pathname = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderScopeError() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
To set your default character
|
||||||
|
we need access to your WoW profile.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://us.battle.net/account/management/authorizations.html"
|
||||||
|
target="_blank">Navigate to your Battle.net Authorized Applications</a></li>
|
||||||
|
<li>Remove Classic WoW Forums</li>
|
||||||
|
<li>Log out and back into Classic WoW Forums</li>
|
||||||
|
<li>Grant Classic WoW Forums access to your WoW profile</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { battletag, character_name, character_class, character_guild, character_realm } = this.props.userStore!.user!;
|
|
||||||
|
if (this.state.noCharacters) {
|
||||||
|
return <div>You have no WoW characters in your account.</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// user must be logged in to view this page
|
||||||
|
if (!this.props.userStore!.user) {
|
||||||
|
return <div></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { battletag, character_name, character_class, character_guild, character_realm, character_avatar } = this.props.userStore!.user!;
|
||||||
|
const { insufficientScope } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollToTop>
|
<ScrollToTop>
|
||||||
<ContentContainer style={{ minHeight: '500px' }}>
|
<ContentContainer style={{ minHeight: '500px', paddingTop: '40px' }}>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<Portrait imageSrc={require('../../assets/Tyren.gif')}/>
|
{character_avatar && <Portrait imageSrc={CharacterService.getAvatar(character_avatar!)}/>}
|
||||||
<div style={{ paddingLeft: '10px' }}>
|
<div style={{ paddingLeft: '10px' }}>
|
||||||
{battletag && <div><b>Battletag: </b>{battletag}</div>}
|
{battletag && <div><b>Battletag: </b>{battletag}</div>}
|
||||||
{character_name && <div><b>Character: </b>{character_name}</div>}
|
{character_name && <div><b>Character: </b>{character_name}</div>}
|
||||||
@@ -120,12 +187,13 @@ export class UserAccount extends React.Component<Props, State> {
|
|||||||
{character_guild && <div><b>Guild: </b>{character_guild}</div>}
|
{character_guild && <div><b>Guild: </b>{character_guild}</div>}
|
||||||
{character_realm && <div><b>Realm: </b>{character_realm}</div>}
|
{character_realm && <div><b>Realm: </b>{character_realm}</div>}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1" style={{ textAlign: 'right' }}>
|
||||||
|
<a onClick={() => this.logout()}>Logout</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Set a new default character</h2>
|
{insufficientScope === true ? this.renderScopeError() : this.renderDropDowns()}
|
||||||
{this.renderDropDowns()}
|
|
||||||
<a onClick={() => this.onSave()}>Save</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
|
|||||||
156
client/app/services/character.service.ts
Normal file
156
client/app/services/character.service.ts
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import { find, filter, get } from 'lodash';
|
||||||
|
import { AvatarModel } from '../model';
|
||||||
|
|
||||||
|
const getAvatar = (title: string): any => {
|
||||||
|
const av = find(avatarList, { title });
|
||||||
|
return get(av, 'imageSrc');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getClass = (index: number): {id: number, name: string; races: number[] } => {
|
||||||
|
return find(classList, { id: index })!;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFilteredAvatarList = (raceIdList: number[]) => {
|
||||||
|
return filter(avatarList, (av) => {
|
||||||
|
return raceIdList.includes(av.raceId);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// taken right from API data
|
||||||
|
const classList = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Warrior',
|
||||||
|
races: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Paladin',
|
||||||
|
races: [1, 3],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Hunter',
|
||||||
|
races: [1, 4, 5, 6, 7],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'Rogue',
|
||||||
|
races: [1, 2, 3, 4, 5, 7, 8],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'Priest',
|
||||||
|
races: [1, 3, 4, 7, 8],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'Shaman',
|
||||||
|
races: [5, 6, 7],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: 'Mage',
|
||||||
|
races: [2, 3, 7, 8],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: 'Warlock',
|
||||||
|
races: [2, 3, 5, 8],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: 'Druid',
|
||||||
|
races: [4, 6],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const avatarList: AvatarModel[] = [
|
||||||
|
{
|
||||||
|
raceId: 1,
|
||||||
|
title: 'dwarf_f',
|
||||||
|
imageSrc: require('../assets/avatars/Dwarf_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 1,
|
||||||
|
title: 'dwarf_m',
|
||||||
|
imageSrc: require('../assets/avatars/Dwarf_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 2,
|
||||||
|
title: 'gnome_f',
|
||||||
|
imageSrc: require('../assets/avatars/Gnome_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 2,
|
||||||
|
title: 'gnome_m',
|
||||||
|
imageSrc: require('../assets/avatars/Gnome_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 3,
|
||||||
|
title: 'human_f',
|
||||||
|
imageSrc: require('../assets/avatars/Human_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 3,
|
||||||
|
title: 'human_m',
|
||||||
|
imageSrc: require('../assets/avatars/Human_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 4,
|
||||||
|
title: 'night_elf_f',
|
||||||
|
imageSrc: require('../assets/avatars/Night_elf_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 4,
|
||||||
|
title: 'night_elf_m',
|
||||||
|
imageSrc: require('../assets/avatars/Night_elf_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 5,
|
||||||
|
title: 'orc_f',
|
||||||
|
imageSrc: require('../assets/avatars/Orc_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 5,
|
||||||
|
title: 'orc_m',
|
||||||
|
imageSrc: require('../assets/avatars/Orc_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 6,
|
||||||
|
title: 'tauren_f',
|
||||||
|
imageSrc: require('../assets/avatars/Tauren_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 6,
|
||||||
|
title: 'tauren_m',
|
||||||
|
imageSrc: require('../assets/avatars/Tauren_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 7,
|
||||||
|
title: 'troll_f',
|
||||||
|
imageSrc: require('../assets/avatars/Troll_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 7,
|
||||||
|
title: 'troll_m',
|
||||||
|
imageSrc: require('../assets/avatars/Troll_male.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 8,
|
||||||
|
title: 'undead_f',
|
||||||
|
imageSrc: require('../assets/avatars/Undead_female.gif'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raceId: 8,
|
||||||
|
title: 'undead_m',
|
||||||
|
imageSrc: require('../assets/avatars/Undead_male.gif'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const CharacterService = {
|
||||||
|
avatarList,
|
||||||
|
getAvatar,
|
||||||
|
getClass,
|
||||||
|
getFilteredAvatarList,
|
||||||
|
};
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './category.service';
|
export * from './category.service';
|
||||||
|
export * from './character.service';
|
||||||
export * from './thread.service';
|
export * from './thread.service';
|
||||||
export * from './user.service';
|
export * from './user.service';
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { chain } from 'lodash';
|
||||||
import axios from '../axios/axios';
|
import axios from '../axios/axios';
|
||||||
import userStore from '../stores/user-store';
|
import userStore from '../stores/user-store';
|
||||||
import { CharacterModel } from '../model';
|
import { CharacterModel } from '../model';
|
||||||
|
import { CharacterService } from './character.service';
|
||||||
|
|
||||||
// fetch user and store in local storage
|
// fetch user and store in local storage
|
||||||
const authorize = async (code: string): Promise<void> => {
|
const authorize = async (code: string): Promise<void> => {
|
||||||
@@ -12,16 +14,31 @@ const authorize = async (code: string): Promise<void> => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCharacters = async (): Promise<CharacterModel | null> => {
|
const getCharacters = async (): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('/api/user/characters');
|
const res = await axios.get('/api/user/characters');
|
||||||
return res.data.data.characters;
|
const characters = res.data.data.characters;
|
||||||
|
if (!!characters) {
|
||||||
|
res.data.data.characters = filterCharacters(characters);
|
||||||
|
}
|
||||||
|
return res.data.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filterCharacters = (chars: CharacterModel[]): CharacterModel[] => {
|
||||||
|
return chain(chars)
|
||||||
|
.filter(c => !!CharacterService.getClass(c.class))
|
||||||
|
.map((c) => {
|
||||||
|
c.races = CharacterService.getClass(c.class).races;
|
||||||
|
c.avatarList = CharacterService.getFilteredAvatarList(c.races);
|
||||||
|
return c;
|
||||||
|
})
|
||||||
|
.value();
|
||||||
|
};
|
||||||
|
|
||||||
const saveCharacter = async (character: any): Promise<any> => {
|
const saveCharacter = async (character: any): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.put('/api/user/characters', character);
|
const res = await axios.put('/api/user/characters', character);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"lib": ["dom", "es7"],
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "es2015",
|
"target": "es2015",
|
||||||
"module": "es2015",
|
"module": "es2015",
|
||||||
|
|||||||
@@ -45,7 +45,12 @@ defmodule MyApp.BattleNet.User do
|
|||||||
defp parse_character_response({:ok, %HTTPoison.Response{body: body}}, user_id) do
|
defp parse_character_response({:ok, %HTTPoison.Response{body: body}}, user_id) do
|
||||||
case Poison.decode(body) do
|
case Poison.decode(body) do
|
||||||
{:ok, data} ->
|
{:ok, data} ->
|
||||||
Cachex.set(:myapp, "usr_char:#{user_id}", data, ttl: :timer.minutes(10)) # 10 minutes
|
# only cache end point if characters return
|
||||||
|
if (!data["characters"]) do
|
||||||
|
{:error, data}
|
||||||
|
else
|
||||||
|
Cachex.set(:myapp, "usr_char:#{user_id}", data, ttl: :timer.minutes(10)) # 10 minutes
|
||||||
|
end
|
||||||
{:ok, data}
|
{:ok, data}
|
||||||
{:error, error} -> {:error, error}
|
{:error, error} -> {:error, error}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ defmodule MyApp.Data.Thread do
|
|||||||
:title,
|
:title,
|
||||||
:view_count,
|
:view_count,
|
||||||
:reply_count,
|
:reply_count,
|
||||||
user: [:id, :battletag],
|
user: [:id, :battletag, :character_guild, :character_name, :character_class, :character_realm, :character_avatar],
|
||||||
last_reply: [:id, :battletag],
|
last_reply: [:id, :battletag, :character_guild, :character_name, :character_class, :character_realm, :character_avatar],
|
||||||
]),
|
]),
|
||||||
where: [category_id: ^category_id],
|
where: [category_id: ^category_id],
|
||||||
preload: [:user, :last_reply]
|
preload: [:user, :last_reply]
|
||||||
|
|||||||
Reference in New Issue
Block a user