Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(market): can list items on market, market interface, etc #92

Merged
merged 9 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class ItemStatsComponent implements OnInit {
const stats = (this.item as IEquipment).stats || {};

Object.keys(stats).forEach((key) => {
if (!stats[key as Stat]) return;
this.stats.push({ key, value: stats[key as Stat] });
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
<ion-title>Compare Items</ion-title>

<ion-buttons slot="end">
<ion-button (click)="dismiss(true)" [strong]="true">Equip</ion-button>
<ion-button (click)="dismiss(true)" [strong]="true" *ngIf="canEquip">
Equip
</ion-button>
<ion-button color="medium" (click)="dismiss()">Close</ion-button>
</ion-buttons>
</ion-toolbar>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ModalController } from '@ionic/angular';
export class CompareItemsModalComponent implements OnInit {
@Input() item1!: IEquipment;
@Input() item2!: IEquipment | undefined;
@Input() canEquip = true;

public commonStats: Stat[] = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class LocationStatsModalComponent implements OnInit {
[LocationStat.LocationFind]: 'Location Find Chance',
[LocationStat.CollectibleFind]: 'Collectible Find Chance',
[LocationStat.ResourceFind]: 'Resource Find Chance',
[LocationStat.TaxRate]: 'Tax Rate',
};

public readonly statFormatters: Record<
Expand All @@ -47,6 +48,7 @@ export class LocationStatsModalComponent implements OnInit {
[LocationStat.LocationFind]: (value) => `${value}%`,
[LocationStat.CollectibleFind]: (value) => `${value}%`,
[LocationStat.ResourceFind]: (value) => `${value}%`,
[LocationStat.TaxRate]: (value) => `${value}%`,
};

constructor(private modalController: ModalController) {}
Expand Down
298 changes: 298 additions & 0 deletions client/src/app/components/modals/market/market.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
<ion-header>
<ion-toolbar>
<ion-title>
Steelrose Market

<small class="available-coins">{{ coins | number }} coins</small>
</ion-title>

<ion-buttons slot="end">
<ion-button
(click)="claimCoins()"
[strong]="true"
color="primary"
*ngIf="unclaimed > 0"
>
Claim {{ unclaimed | number }} coins
</ion-button>

<ion-button
(click)="changeMyListings()"
[strong]="true"
color="secondary"
>
{{ showingMyListings ? 'General Market' : 'My Listings' }}
</ion-button>

<ion-button (click)="close()" [strong]="true">Close</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
<ng-container *ngIf="marketItems$ | async as marketResults">
<ion-row>
<ion-col size="4">
<ion-row>
<ion-col>
<ion-card>
<ion-card-header>
<ion-card-title>Rarities</ion-card-title>
</ion-card-header>

<ion-card-content>
<ion-row>
<ion-col size="4" *ngFor="let rarity of rarities">
<ion-button
expand="block"
[color]="searchRarities[rarity] ? 'secondary' : 'medium'"
(click)="toggleRarity(rarity)"
>
{{ rarity }}
</ion-button>
</ion-col>
</ion-row>
</ion-card-content>
</ion-card>
</ion-col>
</ion-row>

<ion-row>
<ion-col>
<ion-card>
<ion-card-header>
<ion-card-title>Item Types</ion-card-title>
</ion-card-header>

<ion-card-content>
<ion-row>
<ion-col size="4" *ngFor="let type of itemTypes">
<ion-button
expand="block"
[color]="searchTypes[type] ? 'secondary' : 'medium'"
(click)="toggleType(type)"
>
{{ type }}
</ion-button>
</ion-col>
</ion-row>
</ion-card-content>
</ion-card>
</ion-col>
</ion-row>

<ion-row>
<ion-col>
<ion-card>
<ion-card-header>
<ion-card-title>Filters</ion-card-title>
</ion-card-header>

<ion-card-content>
<ion-list>
<ion-item>
<ion-input
label="Item Name"
labelPlacement="stacked"
type="text"
placeholder="Item Name"
[(ngModel)]="searchName"
></ion-input>
</ion-item>

<ion-item>
<ion-input
label="Minimum Level"
labelPlacement="stacked"
type="number"
placeholder="Minimum Level"
[(ngModel)]="searchLevelMin"
></ion-input>
</ion-item>

<ion-item>
<ion-input
label="Maximum Level"
labelPlacement="stacked"
type="number"
placeholder="Maximum Level"
[(ngModel)]="searchLevelMax"
></ion-input>
</ion-item>

<ion-item>
<ion-input
label="Minimum Coin Cost"
labelPlacement="stacked"
type="number"
placeholder="Minimum Coin Cost"
[(ngModel)]="searchCostMin"
></ion-input>
</ion-item>

<ion-item>
<ion-input
label="Maximum Coin Cost"
labelPlacement="stacked"
type="number"
placeholder="Maximum Coin Cost"
[(ngModel)]="searchCostMax"
></ion-input>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
</ion-col>
</ion-row>

<ion-row>
<ion-col>
<ion-button expand="block" color="primary" (click)="search()">
Search
</ion-button>
</ion-col>
</ion-row>
</ion-col>

<ion-col size="8">
<ion-row>
<ion-col>
<ion-card>
<ion-card-header>
<ion-card-title>
<ion-row>
<ion-col size="3" class="title" *ngIf="!showingMyListings">
Market Results
</ion-col>
<ion-col size="3" class="title" *ngIf="showingMyListings">
My Market Listings
</ion-col>

<ion-col size="9" class="pagination-container">
<ion-button
size="small"
(click)="changePage(marketResults.page - 1)"
[disabled]="marketResults.page <= 0"
>
<ion-icon
slot="icon-only"
name="chevron-back"
></ion-icon>
</ion-button>

<span class="text">
Page {{ marketResults.page + 1 }} of
{{ marketResults.lastPage }}
</span>

<ion-button
size="small"
(click)="changePage(marketResults.page + 1)"
[disabled]="
marketResults.page + 1 >= marketResults.lastPage
"
>
<ion-icon
slot="icon-only"
name="chevron-forward"
></ion-icon>
</ion-button>
</ion-col>
</ion-row>
</ion-card-title>
</ion-card-header>

<ion-card-content *ngIf="loading">
<ion-spinner></ion-spinner>
</ion-card-content>

<ion-card-content
*ngIf="!loading && marketResults.results.length === 0"
>
There are no search results at this time.
</ion-card-content>

<ion-card-content
*ngIf="!loading && marketResults.results.length > 0"
>
<ion-list>
<ion-item *ngFor="let item of marketResults.results">
<div slot="start" class="icon-container">
<app-item-icon
[item]="item.itemData"
size="small"
></app-item-icon>

<ion-badge
class="can-equip"
color="success"
*ngIf="canEquipItem(item.itemData)"
[ngxTippy]="'Can equip!'"
>
<ion-icon name="checkmark"></ion-icon>
</ion-badge>
</div>

<ion-label>
<h2>
{{ item.itemData.name }}
<span *ngIf="item.quantity > 0">
x{{ item.quantity }}
</span>
</h2>
<p>
{{ item.itemData.type | titlecase }} &middot;
<strong>{{ item.price | number }} coins</strong>
</p>
<p>
<app-item-stats [item]="item.itemData"></app-item-stats>
</p>
</ion-label>

<ng-container *ngIf="!showingMyListings">
<ion-button
slot="end"
color="secondary"
(click)="compareItem(item.itemData)"
*ngIf="
isEquippableItemType(item.itemData) &&
canCompare(item.itemData)
"
>
<ion-icon name="podium"></ion-icon>

&nbsp;Compare
</ion-button>
</ng-container>

<ng-container *ngIf="showingMyListings">
<ion-button
slot="end"
color="secondary"
(click)="repriceItem(item)"
>
<ion-icon name="repeat"></ion-icon>

&nbsp;Reprice
</ion-button>

<ion-button
slot="end"
color="danger"
(click)="unlistItem(item)"
>
<ion-icon name="archive"></ion-icon>

&nbsp;Unlist
</ion-button>
</ng-container>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
</ion-col>
</ion-row>
</ion-col>
</ion-row>
</ng-container>
</ion-content>
38 changes: 38 additions & 0 deletions client/src/app/components/modals/market/market.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

.available-coins {
font-style: italic;
margin-left: 16px;
}

.title {
display: flex;
align-items: center;
}

.icon-container {
position: relative;

.can-equip {
position: absolute;
top: -7px;
right: -30px;

--padding-top: 1px;
--padding-bottom: 0px;
--padding-start: 2px;
--padding-end: 2px;

font-size: 16px;
}
}

.pagination-container {
display: flex;
justify-content: flex-end;
align-items: center;

.text {
margin-left: 8px;
margin-right: 8px;
}
}
Loading
Loading