makes adding loot working
This commit is contained in:
@@ -138,7 +138,7 @@ impl<'q> AsPlayer<'q> {
|
|||||||
if let Ok((item, diff)) = self.conn.transaction(|| {
|
if let Ok((item, diff)) = self.conn.transaction(|| {
|
||||||
use schema::looted::dsl::*;
|
use schema::looted::dsl::*;
|
||||||
let item = schema::items::table.find(item_id).first::<models::Item>(self.conn)?;
|
let item = schema::items::table.find(item_id).first::<models::Item>(self.conn)?;
|
||||||
let new_item = models::item::NewLoot::to_player(self.id, (&item.name, item.base_price));
|
let new_item = models::item::NewLoot::to_player(self.id, &item);
|
||||||
diesel::insert_into(schema::looted::table)
|
diesel::insert_into(schema::looted::table)
|
||||||
.values(&new_item)
|
.values(&new_item)
|
||||||
.execute(self.conn)?;
|
.execute(self.conn)?;
|
||||||
@@ -285,8 +285,8 @@ impl<'q> AsAdmin<'q> {
|
|||||||
///
|
///
|
||||||
/// # Params
|
/// # Params
|
||||||
/// List of (name, base_price) values for the new items
|
/// List of (name, base_price) values for the new items
|
||||||
pub fn add_loot(self, items: Vec<(&str, i32)>) -> ActionResult<()> {
|
pub fn add_loot(self, items: Vec<models::item::Item>) -> ActionResult<()> {
|
||||||
for item_desc in items.into_iter() {
|
for item_desc in items.iter() {
|
||||||
let new_item = models::item::NewLoot::to_group(item_desc);
|
let new_item = models::item::NewLoot::to_group(item_desc);
|
||||||
diesel::insert_into(schema::looted::table)
|
diesel::insert_into(schema::looted::table)
|
||||||
.values(&new_item)
|
.values(&new_item)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type OwnedBy = Select<OwnedLoot, ItemColumns>;
|
|||||||
/// It is also used as a public representation of Loot, since owner
|
/// It is also used as a public representation of Loot, since owner
|
||||||
/// information is implicit.
|
/// information is implicit.
|
||||||
/// Or maybe this is a little too confusing ??
|
/// Or maybe this is a little too confusing ??
|
||||||
#[derive(Debug, Queryable, Serialize)]
|
#[derive(Debug, Queryable, Serialize, Deserialize, Clone)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -54,9 +54,6 @@ impl Loot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Description of an item : (name, value in gold)
|
|
||||||
pub type ItemDesc<'a> = (&'a str, i32);
|
|
||||||
|
|
||||||
/// An item being looted or bought.
|
/// An item being looted or bought.
|
||||||
///
|
///
|
||||||
/// The owner is set to 0 in case of looting,
|
/// The owner is set to 0 in case of looting,
|
||||||
@@ -71,19 +68,19 @@ pub(crate) struct NewLoot<'a> {
|
|||||||
|
|
||||||
impl<'a> NewLoot<'a> {
|
impl<'a> NewLoot<'a> {
|
||||||
/// A new loot going to the group (loot procedure)
|
/// A new loot going to the group (loot procedure)
|
||||||
pub(crate) fn to_group(desc: ItemDesc<'a>) -> Self {
|
pub(crate) fn to_group(desc: &'a Item) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: desc.0,
|
name: &desc.name,
|
||||||
base_price: desc.1,
|
base_price: desc.base_price,
|
||||||
owner_id: 0,
|
owner_id: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A new loot going to a specific player (buy procedure)
|
/// A new loot going to a specific player (buy procedure)
|
||||||
pub(crate) fn to_player(player: i32, desc: ItemDesc<'a>) -> Self {
|
pub(crate) fn to_player(player: i32, desc: &'a Item) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: desc.0,
|
name: &desc.name,
|
||||||
base_price: desc.1,
|
base_price: desc.base_price,
|
||||||
owner_id: player,
|
owner_id: player,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ pub(super) mod item;
|
|||||||
pub(super) mod player;
|
pub(super) mod player;
|
||||||
|
|
||||||
pub use claim::Claim;
|
pub use claim::Claim;
|
||||||
pub use item::Item;
|
pub use item::{Item};
|
||||||
pub(crate) use item::Loot;
|
pub(crate) use item::Loot;
|
||||||
pub use player::{Player, Wealth};
|
pub use player::{Player, Wealth};
|
||||||
|
|||||||
@@ -56,13 +56,11 @@
|
|||||||
</nav>
|
</nav>
|
||||||
<main class="section">
|
<main class="section">
|
||||||
<template v-if="isAdding">
|
<template v-if="isAdding">
|
||||||
<div v-if="playerIsGroup" class="box">
|
<Loot v-if="playerIsGroup"
|
||||||
<ItemInput v-if="playerIsGroup"
|
:inventory="state.inventory"
|
||||||
:source="state.inventory"
|
@addItem="item => pending_loot.push(item)"
|
||||||
@addItem="item => pending_loot.push(item)"
|
@confirmAction="addNewLoot"
|
||||||
></ItemInput>
|
></Loot>
|
||||||
<button>Envoyer</button>
|
|
||||||
</div>
|
|
||||||
<AddingChest
|
<AddingChest
|
||||||
:items="playerIsGroup ? pending_loot : state.inventory"
|
:items="playerIsGroup ? pending_loot : state.inventory"
|
||||||
:perms="playerIsGroup ? {} : { canBuy: true }"
|
:perms="playerIsGroup ? {} : { canBuy: true }"
|
||||||
@@ -89,8 +87,8 @@ import PlayerView from './components/PlayerView.js'
|
|||||||
import HeaderBar from './components/HeaderBar.vue'
|
import HeaderBar from './components/HeaderBar.vue'
|
||||||
import Wealth from './components/Wealth.vue'
|
import Wealth from './components/Wealth.vue'
|
||||||
import Chest from './components/Chest.vue'
|
import Chest from './components/Chest.vue'
|
||||||
import ItemInput from './components/ItemInput.vue'
|
import Loot from './components/Loot.vue'
|
||||||
import { AppStorage } from './AppStorage'
|
import { Api, AppStorage } from './AppStorage'
|
||||||
|
|
||||||
function getCookie(cname) {
|
function getCookie(cname) {
|
||||||
var name = cname + "=";
|
var name = cname + "=";
|
||||||
@@ -124,7 +122,7 @@ export default {
|
|||||||
'AddingChest': Chest, // Alias to prevent component re-use
|
'AddingChest': Chest, // Alias to prevent component re-use
|
||||||
Chest,
|
Chest,
|
||||||
Wealth,
|
Wealth,
|
||||||
ItemInput,
|
Loot,
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
// Initiate with active player set to value found in cookie
|
// Initiate with active player set to value found in cookie
|
||||||
@@ -149,7 +147,16 @@ export default {
|
|||||||
}
|
}
|
||||||
this.activeView = viewId;
|
this.activeView = viewId;
|
||||||
},
|
},
|
||||||
switchPlayerChestVisibility () { AppStorage.switchPlayerChestVisibility(); },
|
switchPlayerChestVisibility () {
|
||||||
|
AppStorage.switchPlayerChestVisibility();
|
||||||
|
},
|
||||||
|
addNewLoot () {
|
||||||
|
Api.newLoot(this.pending_loot)
|
||||||
|
.then(_ => {
|
||||||
|
this.pending_loot = []
|
||||||
|
this.switchView('group');
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showPlayerChest () { return this.activeView == 'player' },
|
showPlayerChest () { return this.activeView == 'player' },
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ export const Api = {
|
|||||||
sellItems (player_id, items) {
|
sellItems (player_id, items) {
|
||||||
const payload = { player_id, items };
|
const payload = { player_id, items };
|
||||||
return this.__doFetch("players/sell", 'POST', payload);
|
return this.__doFetch("players/sell", 'POST', payload);
|
||||||
|
},
|
||||||
|
newLoot (items) {
|
||||||
|
return this.__doFetch("admin/add-loot", 'POST', items);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -165,6 +167,9 @@ export const AppStorage = {
|
|||||||
if (this.debug) console.log("cancel a non-existent request")
|
if (this.debug) console.log("cancel a non-existent request")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
addNewLoot (items) {
|
||||||
|
return Api.newLoot(items);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container is-paddingless">
|
<div class="field is-horizontal">
|
||||||
<p class="heading">Ajouter un objet</p>
|
<div class="field-label">
|
||||||
<div class="field">
|
<label class="label">Nouvel objet</label>
|
||||||
<label for="item_name" class="label">Nom</label>
|
</div>
|
||||||
<div class="control is-expanded" :class="{'is-loading': is_loading }">
|
<div class="field-body">
|
||||||
<input type="text"
|
<div class="field">
|
||||||
id="item_name"
|
<div class="control is-expanded">
|
||||||
v-model="item.name"
|
<input type="text"
|
||||||
@input="autoCompletion"
|
placeholder="Nom de l'objet"
|
||||||
class="input"
|
v-model="item.name"
|
||||||
autocomplete="on"
|
@input="autoCompletion"
|
||||||
></input>
|
class="input"
|
||||||
</div>
|
autocomplete="on"
|
||||||
<div class="dropdown" :class="{'is-active': showCompletionFrame}">
|
>
|
||||||
<div class="dropdown-menu">
|
</div>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown" :class="{'is-active': showCompletionFrame}">
|
||||||
<a v-for="(result,i) in results"
|
<div class="dropdown-menu">
|
||||||
:key="i"
|
<div class="dropdown-content">
|
||||||
@click="setResult(result)"
|
<a v-for="(result,i) in results"
|
||||||
class="dropdown-item"
|
:key="i"
|
||||||
>{{ result.name }}</a>
|
@click="setResult(result)"
|
||||||
|
class="dropdown-item"
|
||||||
|
>{{ result.name }}</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="field is-expanded has-addons" v-show="item.name != ''">
|
||||||
<div class="field">
|
<p class="control"><a class="button is-static">PO</a></p>
|
||||||
<div class="control">
|
<p class="control">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
class="input"
|
placeholder="Prix"
|
||||||
:class="{'is-danger': item.base_price == ''}"
|
class="input"
|
||||||
v-model.number="item.base_price"
|
:class="{'is-danger': item.base_price == ''}"
|
||||||
></input>
|
v-model.number="item.base_price"
|
||||||
|
>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="field">
|
||||||
<button class="button is-primary"
|
<div class="control">
|
||||||
@click="addItem"
|
<button class="button is-primary"
|
||||||
>+</button>
|
@click="addItem"
|
||||||
|
:disabled="!isItemValid"
|
||||||
|
>Ajouter</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -49,6 +56,7 @@
|
|||||||
return {
|
return {
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
item: {
|
item: {
|
||||||
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
base_price: '',
|
base_price: '',
|
||||||
},
|
},
|
||||||
@@ -59,7 +67,6 @@
|
|||||||
autoCompletion () {
|
autoCompletion () {
|
||||||
// Unset any previous value on input (for every field except item's name)
|
// Unset any previous value on input (for every field except item's name)
|
||||||
this.item.base_price = '';
|
this.item.base_price = '';
|
||||||
|
|
||||||
if (this.item.name == '') {
|
if (this.item.name == '') {
|
||||||
this.results = [];
|
this.results = [];
|
||||||
} else {
|
} else {
|
||||||
@@ -69,13 +76,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setResult(result) {
|
setResult(result) {
|
||||||
|
this.item.id = result.id;
|
||||||
this.item.name = result.name;
|
this.item.name = result.name;
|
||||||
this.item.base_price = result.base_price;
|
this.item.base_price = result.base_price;
|
||||||
// Clear results to close completionFrame
|
// Clear results to close completionFrame
|
||||||
this.results = [];
|
this.results = [];
|
||||||
},
|
},
|
||||||
addItem () {
|
addItem () {
|
||||||
// TODO: check item is valid
|
|
||||||
this.$emit("addItem", this.item);
|
this.$emit("addItem", this.item);
|
||||||
this.item = {
|
this.item = {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -86,11 +93,15 @@
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showCompletionFrame () { return this.results.length > 0 },
|
showCompletionFrame () { return this.results.length > 0 },
|
||||||
|
isItemValid () { return this.item.name != '' && this.item.base_price != '' },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.dropdown, .dropdown-menu { min-width: 100%; margin-top: 0; padding-top: 0;}
|
.dropdown, .dropdown-menu {
|
||||||
/*.dropdown { top: -0.75rem; }*/
|
min-width: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,37 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="box">
|
||||||
<p class="heading has-text-left is-size-5">
|
<ItemInput
|
||||||
Nouveau loot - {{ looted.length }} objet(s)</p>
|
@addItem="onAddItem"
|
||||||
<ItemInput @addItem="onAddItem" :source="inventory"></ItemInput>
|
:source="inventory"
|
||||||
<p v-for="(item, idx) in looted" :key="idx"
|
></ItemInput>
|
||||||
class="has-text-left is-size-5">
|
<div class="field is-horizontal">
|
||||||
{{ item.name }} ({{ item.sell_value }}po)
|
<div class="field-label"><label class="label">ou</label></div>
|
||||||
</p>
|
<div class="field-body">
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<button class="button is-primary">Depuis une liste</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="button is-danger" @click="$emit('confirmAction')">Finaliser</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ItemInput from './ItemInput.vue'
|
import ItemInput from './ItemInput.vue'
|
||||||
// List of items for autocomplete
|
|
||||||
const MOCK_ITEMS = [
|
|
||||||
{id: 35, name: "Cape d'invisibilité", sell_value: 30000},
|
|
||||||
{id: 8, name: "Arc long", sell_value: 10},
|
|
||||||
{id: 9, name: "Arc court", sell_value: 10},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
props: ["inventory"],
|
||||||
components: { ItemInput },
|
components: { ItemInput },
|
||||||
data () { return {
|
data () { return {}; },
|
||||||
looted: [],
|
|
||||||
inventory: MOCK_ITEMS,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
onAddItem (item) {
|
onAddItem (item) {
|
||||||
this.looted.push(item);
|
this.$emit('addItem', item);
|
||||||
},
|
|
||||||
onClose () {
|
|
||||||
this.$emit('done');
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use actix_files as fs;
|
|||||||
use actix_web::{web, App, Error, HttpResponse, HttpServer};
|
use actix_web::{web, App, Error, HttpResponse, HttpServer};
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use lootalot_db::{DbApi, Pool, QueryResult};
|
use lootalot_db::{DbApi, Pool, QueryResult};
|
||||||
|
use lootalot_db::models::Item;
|
||||||
use std::env;
|
use std::env;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
@@ -162,6 +163,17 @@ pub(crate) fn serve() -> std::io::Result<()> {
|
|||||||
db_call(pool, move |api| api.as_admin().resolve_claims())
|
db_call(pool, move |api| api.as_admin().resolve_claims())
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/add-loot",
|
||||||
|
web::post().to_async(
|
||||||
|
move |pool: AppPool, data: web::Json<Vec<Item>>| {
|
||||||
|
db_call(pool, move |api| api
|
||||||
|
.as_admin()
|
||||||
|
.add_loot(data.to_vec()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/add-player",
|
"/add-player",
|
||||||
web::get().to_async(
|
web::get().to_async(
|
||||||
|
|||||||
Reference in New Issue
Block a user