[MIRROR] You can sell stuff on the blackmarket now. (#29401)

* You can sell stuff on the blackmarket now. (#85464)

## About The Pull Request
The idea came up during the last blackmarket-related PR (#85066), when
the original creator @ TheChosenEvilOne came and said the LTSRBT was
originally supposed to allow players to sell stuff on the blackmarket. I
replied saying the idea has some potential, and then other github users
followed, also saying it's a good idea.

So, here we are, adding another feature to the LTSRBT, to let you
provide other players with potentially knock-offs and fraudulent (or
genuinely honest) items on the blackmarket.

How you do it is fairly simple: left click the machine to open it, place
the item inside, then right-click to open the UI. From there you can
adjust the name, description and price of the market item. Finally,
click on the "Place on Market" button twice, pay a 30 credits fee, and
it's done. You have an item on the market, and once it's sold, 85% or
the earnings (the price) will be deposited on your account.

By the by, the icon of the item you're trying to sell will also show up
on the market. You should get a picture of what you're getting before
falling for an obvious scam.

![screenie](https://github.com/user-attachments/assets/fae70c25-ab46-4ceb-af9e-f4818d8a1c68)

By the by, it's a cardboard cutout.

## Why It's Good For The Game
This fits the design of the LTSRBT and blackmarket in general.

## Changelog

🆑
add: You can sell items on the blackmarket with the LTSRBT now.
fix: Added some checks to prevent the swapper device and bluespace
anomalies from theorically being able to send things and people to
nullspace.
/🆑

---------

Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@ users.noreply.github.com>

* You can sell stuff on the blackmarket now.

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@ users.noreply.github.com>
This commit is contained in:
SkyratBot
2024-08-17 15:22:14 +02:00
committed by GitHub
parent a97d2a75dc
commit e80dc84617
12 changed files with 416 additions and 48 deletions

View File

@@ -10,3 +10,5 @@
// Sends a supply pod to the buyer's location, showy. // Sends a supply pod to the buyer's location, showy.
#define SHIPPING_METHOD_SUPPLYPOD "Supply Pod" #define SHIPPING_METHOD_SUPPLYPOD "Supply Pod"
/// The percentage on gains that's removed when selling an item through the blackmarket with the LTSRBT
#define MARKET_WITHHOLDING_TAX 0.15

View File

@@ -31,8 +31,16 @@
// Calculate new position (searches through beacons in world) // Calculate new position (searches through beacons in world)
var/obj/item/beacon/chosen var/obj/item/beacon/chosen
var/list/possible = list() var/list/possible = list()
for(var/obj/item/beacon/W in GLOB.teleportbeacons) for(var/obj/item/beacon/beacon in GLOB.teleportbeacons)
possible += W var/turf/turf = get_turf(beacon)
if(!turf)
continue
if(is_centcom_level(turf.z) || is_away_level(turf.z))
continue
var/area/area = get_area(turf)
if(!area || (area.area_flags & NOTELEPORT))
continue
possible += beacon
if(possible.len > 0) if(possible.len > 0)
chosen = pick(possible) chosen = pick(possible)

View File

@@ -103,7 +103,7 @@
return teleportable return teleportable
/obj/item/swapper/proc/swap(mob/user) /obj/item/swapper/proc/swap(mob/user)
if(QDELETED(linked_swapper) || world.time < linked_swapper.cooldown) if(QDELETED(linked_swapper) || isnull(linked_swapper.loc) || world.time < linked_swapper.cooldown)
return return
var/atom/movable/A = get_teleportable_container() var/atom/movable/A = get_teleportable_container()

View File

@@ -30,6 +30,9 @@
/// Probability for this item to be available. Used by SSmarket on init. /// Probability for this item to be available. Used by SSmarket on init.
var/availability_prob var/availability_prob
/// If set, this icon will be shown in the UI.
var/html_icon
///The identifier for the market item, generated on runtime and used to access them in the market categories. ///The identifier for the market item, generated on runtime and used to access them in the market categories.
var/identifier var/identifier
@@ -51,9 +54,11 @@
//we're replacing the item to sell, and the old item is an instance! //we're replacing the item to sell, and the old item is an instance!
if(ismovable(item)) if(ismovable(item))
UnregisterSignal(item, COMSIG_QDELETING) UnregisterSignal(item, COMSIG_QDELETING)
html_icon = null
item = path_or_ref item = path_or_ref
identifier = "[path_or_ref]" identifier = "[path_or_ref]"
if(ismovable(path_or_ref)) if(ismovable(path_or_ref))
html_icon = icon2base64(getFlatIcon(item, no_anim=TRUE))
RegisterSignal(item, COMSIG_QDELETING, PROC_REF(on_item_del)) RegisterSignal(item, COMSIG_QDELETING, PROC_REF(on_item_del))
identifier = "[REF(src)]" identifier = "[REF(src)]"

View File

@@ -0,0 +1,25 @@
///A special category for goods placed on the market by station by someone with the LTSRBT.
/datum/market_item/local_good
category = "Local Goods"
abstract_path = /datum/market_item/local_good
stock = 1
availability_prob = 100
restockable = FALSE
var/datum/bank_account/seller
/datum/market_item/local_good/New(atom/movable/thing, datum/bank_account/seller)
..()
set_item(thing)
src.seller = seller
if(seller)
RegisterSignal(seller, COMSIG_QDELETING, PROC_REF(delete_reference))
/datum/market_item/local_good/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method, legal_status)
. = ..()
if(. && seller)
seller.adjust_money(round(price * (1 - MARKET_WITHHOLDING_TAX)), "Market: Item Sold")
QDEL_IN(src, 10 MINUTES) //This category cannot hold more than 40 items at a time, so we need to clear sold items.
/datum/market_item/local_good/proc/delete_reference(datum/source)
SIGNAL_HANDLER
seller = null

View File

@@ -1,4 +1,5 @@
#define DEFAULT_RESTOCK_COST 675 #define DEFAULT_RESTOCK_COST CARGO_CRATE_VALUE * 3.375
#define PLACE_ON_MARKET_COST PAYCHECK_LOWER * 1.2
/obj/item/circuitboard/machine/ltsrbt /obj/item/circuitboard/machine/ltsrbt
name = "LTSRBT (Machine Board)" name = "LTSRBT (Machine Board)"
@@ -14,13 +15,14 @@
/obj/machinery/ltsrbt /obj/machinery/ltsrbt
name = "Long-To-Short-Range-Bluespace-Transceiver" name = "Long-To-Short-Range-Bluespace-Transceiver"
desc = "The LTSRBT is a compact teleportation machine for receiving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n" desc = "The LTSRBT is a compact teleportation machine for receiving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n"
icon = 'icons/obj/machines/telecomms.dmi' icon = 'icons/obj/machines/ltsrbt.dmi'
icon_state = "exonet_node_idle" icon_state = "ltsrbt_idle"
base_icon_state = "exonet_node" base_icon_state = "ltsrbt"
circuit = /obj/item/circuitboard/machine/ltsrbt circuit = /obj/item/circuitboard/machine/ltsrbt
density = TRUE density = TRUE
idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2 idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND
/// Divider for energy_usage_per_teleport. /// Divider for energy_usage_per_teleport.
var/power_efficiency = 1 var/power_efficiency = 1
@@ -38,6 +40,12 @@
var/datum/market_purchase/transmitting var/datum/market_purchase/transmitting
/// Queue for purchases that the machine should receive and send. /// Queue for purchases that the machine should receive and send.
var/list/datum/market_purchase/queue = list() var/list/datum/market_purchase/queue = list()
/// The name of the market item that we've set on the UI
var/current_name = ""
/// The desc of the market item that we've set on the UI
var/current_desc = ""
/// The price of the market item that we've set on the UI
var/current_price = CARGO_CRATE_VALUE
/** /**
* Attacking the machinery with enough credits will restock the markets, allowing for more/better items. * Attacking the machinery with enough credits will restock the markets, allowing for more/better items.
* The cost doubles each time this is done. * The cost doubles each time this is done.
@@ -48,32 +56,267 @@
. = ..() . = ..()
register_context() register_context()
SSmarket.telepads += src SSmarket.telepads += src
ADD_TRAIT(src, TRAIT_SECLUDED_LOCATION, INNATE_TRAIT) //you cannot sell disky, boss.
update_appearance()
/obj/machinery/ltsrbt/Destroy() /obj/machinery/ltsrbt/Destroy()
SSmarket.telepads -= src SSmarket.telepads -= src
// Bye bye orders. // Bye bye orders.
if(length(SSmarket.telepads)) if(length(SSmarket.telepads))
for(var/datum/market_purchase/P in queue) for(var/datum/market_purchase/purchase in queue)
SSmarket.queue_item(P) SSmarket.queue_item(purchase)
. = ..() if(receiving)
SSmarket.queue_item(receiving)
queue = null
receiving = null
transmitting = null
return ..()
/obj/machinery/ltsrbt/add_context(atom/source, list/context, obj/item/held_item, mob/user) /obj/machinery/ltsrbt/add_context(atom/source, list/context, obj/item/held_item, mob/user)
if(held_item && held_item.get_item_credit_value()) if(held_item)
if(state_open)
context[SCREENTIP_CONTEXT_LMB] = "Insert"
return CONTEXTUAL_SCREENTIP_SET
if(held_item.get_item_credit_value() && !(machine_stat & NOPOWER))
context[SCREENTIP_CONTEXT_LMB] = "Restock" context[SCREENTIP_CONTEXT_LMB] = "Restock"
return CONTEXTUAL_SCREENTIP_SET return CONTEXTUAL_SCREENTIP_SET
return NONE return NONE
if(state_open)
context[SCREENTIP_CONTEXT_LMB] = "Close"
return CONTEXTUAL_SCREENTIP_SET
context[SCREENTIP_CONTEXT_LMB] = "Open"
if(occupant && !(machine_stat & NOPOWER))
context[SCREENTIP_CONTEXT_RMB] = "Place on market"
return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/ltsrbt/examine(mob/user) /obj/machinery/ltsrbt/examine(mob/user)
. = ..() . = ..()
if(machine_stat & NOPOWER) if(!(machine_stat & NOPOWER))
. += span_info("A display reads: \"Current market restock price: [EXAMINE_HINT("[restock_cost] cr")]\".") . += span_info("A small display reads:")
. += span_tinynoticeital("Current market restock price: [EXAMINE_HINT("[restock_cost] cr")].")
. += span_tinynoticeital("Market placement fee: [EXAMINE_HINT("[PLACE_ON_MARKET_COST] cr")].")
. += span_tinynoticeital("Withholding tax on local items: [EXAMINE_HINT("[MARKET_WITHHOLDING_TAX * 100]%")].")
/obj/machinery/ltsrbt/update_icon_state() /obj/machinery/ltsrbt/update_icon_state()
. = ..() . = ..()
if(machine_stat & NOPOWER) if(machine_stat & NOPOWER)
icon_state = "[base_icon_state]_off" icon_state = "[base_icon_state]_off"
else else
icon_state = "[base_icon_state][(receiving || length(queue)) ? "" : "_idle"]" icon_state = "[base_icon_state][(receiving || length(queue) || occupant) ? "" : "_idle"]"
/obj/machinery/ltsrbt/update_overlays()
. = ..()
if(!state_open)
. += "[base_icon_state]_closed"
else
var/mutable_appearance/overlay = mutable_appearance(icon, "[base_icon_state]_open")
overlay.pixel_w -= 2
overlay.pixel_z -= 1
. += overlay
/obj/machinery/ltsrbt/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
if(!state_open)
open_machine(density_to_set = TRUE)
else
close_machine()
/obj/machinery/ltsrbt/open_machine(drop = TRUE, density_to_set = FALSE)
. = ..()
playsound(src, 'sound/machines/oven/oven_open.ogg', 75, TRUE)
/obj/machinery/ltsrbt/close_machine(atom/movable/target, density_to_set = TRUE)
. = ..()
playsound(src, 'sound/machines/oven/oven_close.ogg', 75, TRUE)
/obj/machinery/ltsrbt/set_occupant(obj/item/new_occupant)
. = ..()
if(new_occupant)
current_name = new_occupant.name
current_desc = new_occupant.desc
/obj/machinery/ltsrbt/can_be_occupant(atom/movable/atom)
return isitem(atom) && !atom.anchored
/obj/machinery/ltsrbt/Exited(atom/movable/gone)
if(gone == occupant)
current_price = initial(current_price)
current_name = ""
current_desc = ""
update_appearance(UPDATE_ICON_STATE)
return ..()
/obj/machinery/ltsrbt/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(state_open)
balloon_alert(user, "close it first!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!occupant)
balloon_alert(user, "nothing loaded!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(machine_stat & NOPOWER)
balloon_alert(user, "machine unpowered!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!COOLDOWN_FINISHED(src, recharge_cooldown))
balloon_alert(user, "on cooldown!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
ui_interact(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/machinery/ltsrbt/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(user.combat_mode)
return NONE
var/creds_value = tool.get_item_credit_value()
if(state_open)
if(locate(/mob/living) in tool.get_all_contents())
say("Living being detected, cannot sell!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return ITEM_INTERACT_BLOCKING
if(!user.transferItemToLoc(tool, src))
balloon_alert(user, "stuck to your hands!")
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "item loaded")
close_machine(tool)
return ITEM_INTERACT_SUCCESS
else if(!creds_value)
balloon_alert(user, "open the machine!")
return ITEM_INTERACT_BLOCKING
if(machine_stat & NOPOWER)
return
if(creds_value < restock_cost)
say("Insufficient credits!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return ITEM_INTERACT_BLOCKING
if(istype(tool, /obj/item/holochip))
var/obj/item/holochip/chip = tool
chip.spend(restock_cost)
else
qdel(tool)
if(creds_value != restock_cost)
var/obj/item/holochip/change = new(loc, creds_value - restock_cost)
user.put_in_hands(change)
SSmarket.restock()
restock_cost *= 2
return ITEM_INTERACT_SUCCESS
/obj/machinery/ltsrbt/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "LTSRBT", name)
ui.open()
/obj/machinery/ltsrbt/ui_state()
if(!occupant || !COOLDOWN_FINISHED(src, recharge_cooldown))
return GLOB.never_state //close it.
else
return GLOB.default_state
#define LTSRBT_MIN_PRICE PAYCHECK_LOWER
#define LTSRBT_MAX_PRICE CARGO_CRATE_VALUE * 50
/obj/machinery/ltsrbt/ui_static_data(mob/user)
var/list/data = list()
data["loaded_icon"] = icon2base64(getFlatIcon(occupant, no_anim=TRUE))
data["min_price"] = LTSRBT_MIN_PRICE
data["max_price"] = LTSRBT_MAX_PRICE
return data
/obj/machinery/ltsrbt/ui_data(mob/user)
var/list/data = list()
data["name"] = current_name
data["price"] = current_price
data["desc"] = current_desc
return data
/obj/machinery/ltsrbt/ui_act(action, list/params)
. = ..()
if(.)
return
switch(action)
if("change_name")
var/value = params["value"]
if(!CAN_BYPASS_FILTER(usr) && is_ic_filtered_for_pdas(value))
return TRUE
current_name = trim(value, MAX_NAME_LEN)
return TRUE
if("change_desc")
var/value = params["value"]
if(!CAN_BYPASS_FILTER(usr) && is_ic_filtered_for_pdas(value))
return TRUE
current_desc = trim(value, MAX_DESC_LEN)
return TRUE
if("change_price")
current_price = clamp(params["value"], LTSRBT_MIN_PRICE, LTSRBT_MAX_PRICE)
return TRUE
if("place_on_market")
place_on_market(usr)
return TRUE
#undef LTSRBT_MIN_PRICE
#undef LTSRBT_MAX_PRICE
#define LTSRBT_MAX_MARKET_ITEMS 40
/obj/machinery/ltsrbt/proc/place_on_market(mob/user)
if(QDELETED(occupant))
return
if(locate(/mob/living) in occupant.get_all_contents())
say("Living being detected, cannot sell!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return
var/datum/bank_account/account
var/datum/market/our_market = SSmarket.markets[/datum/market/blackmarket]
if(!isAdminGhostAI(user))
if(!isliving(user))
return
if(length(our_market.available_items[/datum/market_item/local_good::category]) >= LTSRBT_MAX_MARKET_ITEMS)
say("Local market saturated, buy some goods first!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return
var/mob/living/living_user = user
var/obj/item/card/id/card = living_user.get_idcard(TRUE)
if(!(card?.registered_account))
say("No bank account to charge market fees detected!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return
if(!card.registered_account.adjust_money(-PLACE_ON_MARKET_COST, "Market: Placement Fee"))
say("Insufficient credits!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return
account = card.registered_account
var/obj/item/item = occupant //occupant, name, price and desc will be null'd once it exits the machine so we need this.
var/name_to_use = current_name || item.name
var/desc_to_use = current_desc
if(account)
desc_to_use += "[current_desc ? " - " : ""]Seller: [account.account_holder]"
var/price_to_use = current_price
item.moveToNullspace()
//Something happened and the item was deleted or relocated as soon as it was moved to nullspace.
if(QDELETED(item) || item.loc != null)
say("Runtime at market_placement.dm, line 153: item gone!") //metajoke
return
var/datum/market_item/local_good/new_item = new(item, account)
new_item.name = name_to_use
new_item.desc = desc_to_use
new_item.price = price_to_use
our_market.add_item(new_item)
say("Item placed on the market!")
playsound(src, 'sound/effects/cashregister.ogg', 40, FALSE)
COOLDOWN_START(src, recharge_cooldown, recharge_time * 3)
#undef LTSRBT_MAX_MARKET_ITEMS
/obj/machinery/ltsrbt/RefreshParts() /obj/machinery/ltsrbt/RefreshParts()
. = ..() . = ..()
@@ -81,7 +324,6 @@
// On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1. // On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1.
for(var/datum/stock_part/scanning_module/scanning_module in component_parts) for(var/datum/stock_part/scanning_module/scanning_module in component_parts)
recharge_time -= scanning_module.tier * 1 SECONDS recharge_time -= scanning_module.tier * 1 SECONDS
recharge_cooldown = recharge_time
power_efficiency = 0 power_efficiency = 0
for(var/datum/stock_part/micro_laser/laser in component_parts) for(var/datum/stock_part/micro_laser/laser in component_parts)
@@ -132,43 +374,17 @@
transmitting = receiving transmitting = receiving
receiving = null receiving = null
COOLDOWN_START(src, recharge_cooldown, recharge_time)
return return
if(transmitting) if(transmitting)
if(transmitting.item.loc == turf) if(transmitting.item.loc == turf)
do_teleport(transmitting.item, get_turf(transmitting.uplink)) do_teleport(transmitting.item, get_turf(transmitting.uplink))
use_energy(energy_usage_per_teleport / power_efficiency) use_energy(energy_usage_per_teleport / power_efficiency)
QDEL_NULL(transmitting) QDEL_NULL(transmitting)
COOLDOWN_START(src, recharge_cooldown, recharge_time)
return return
if(length(queue)) if(length(queue))
receiving = pick_n_take(queue) receiving = pick_n_take(queue)
/obj/machinery/ltsrbt/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
var/creds_value = tool.get_item_credit_value()
if(!creds_value)
return NONE
. = ITEM_INTERACT_SUCCESS
if(machine_stat & NOPOWER)
return
if(creds_value < restock_cost)
say("Insufficient credits!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
return
if(istype(tool, /obj/item/holochip))
var/obj/item/holochip/chip = tool
chip.spend(restock_cost)
else
qdel(tool)
if(creds_value != restock_cost)
var/obj/item/holochip/change = new(creds_value - restock_cost)
user.put_in_hands(change)
SSmarket.restock()
restock_cost *= 2
#undef DEFAULT_RESTOCK_COST #undef DEFAULT_RESTOCK_COST
#undef PLACE_ON_MARKET_COST

View File

@@ -80,7 +80,8 @@
"name" = item.name, "name" = item.name,
"cost" = item.price, "cost" = item.price,
"amount" = item.stock, "amount" = item.stock,
"desc" = item.desc || item.name "desc" = item.desc || item.name,
"html_icon" = item.html_icon,
)) ))
return data return data

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -3790,6 +3790,7 @@
#include "code\modules\cargo\markets\market_items\clothing.dm" #include "code\modules\cargo\markets\market_items\clothing.dm"
#include "code\modules\cargo\markets\market_items\consumables.dm" #include "code\modules\cargo\markets\market_items\consumables.dm"
#include "code\modules\cargo\markets\market_items\hostages.dm" #include "code\modules\cargo\markets\market_items\hostages.dm"
#include "code\modules\cargo\markets\market_items\local_goods.dm"
#include "code\modules\cargo\markets\market_items\misc.dm" #include "code\modules\cargo\markets\market_items\misc.dm"
#include "code\modules\cargo\markets\market_items\stolen_goods.dm" #include "code\modules\cargo\markets\market_items\stolen_goods.dm"
#include "code\modules\cargo\markets\market_items\tools.dm" #include "code\modules\cargo\markets\market_items\tools.dm"

View File

@@ -2,6 +2,7 @@ import {
AnimatedNumber, AnimatedNumber,
Box, Box,
Button, Button,
Image,
Modal, Modal,
Section, Section,
Stack, Stack,
@@ -36,6 +37,7 @@ type Item = {
desc: string; desc: string;
amount: number; amount: number;
cost: number; cost: number;
html_icon: string;
}; };
type DeliveryMethod = { type DeliveryMethod = {
@@ -106,9 +108,23 @@ export const BlackMarketUplink = (props) => {
{items.map((item) => ( {items.map((item) => (
<Box key={item.name} className="candystripe" p={1} pb={2}> <Box key={item.name} className="candystripe" p={1} pb={2}>
<Stack align="baseline"> <Stack align="baseline">
<Stack.Item grow>
<Stack align="horizontal">
{!!item.html_icon && (
<Stack.Item>
<Image
m={1}
src={`data:image/jpeg;base64,${item.html_icon}`}
height="64px"
width="64px"
/>
</Stack.Item>
)}
<Stack.Item grow bold> <Stack.Item grow bold>
{item.name} {item.name}
</Stack.Item> </Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item color="label"> <Stack.Item color="label">
{item.amount ? item.amount + ' in stock' : 'Out of stock'} {item.amount ? item.amount + ' in stock' : 'Out of stock'}
</Stack.Item> </Stack.Item>

View File

@@ -0,0 +1,94 @@
import { useBackend } from '../backend';
import {
Button,
Image,
Input,
NumberInput,
Section,
Stack,
TextArea,
} from '../components';
import { Window } from '../layouts';
type Data = {
name: string;
price: number;
min_price: number;
max_price: number;
loaded_icon: string;
desc: string;
};
export const LTSRBT = (props) => {
const { act, data } = useBackend<Data>();
const { name, price, min_price, max_price, loaded_icon, desc } = data;
return (
<Window width={300} height={380} theme="hackerman">
<Window.Content>
<Stack vertical fill>
<Stack.Item>
<Input
width="80%"
value={name}
placeholder="Insert a name"
onChange={(e, value) =>
act('change_name', {
value: value,
})
}
/>
<NumberInput
step={1}
width="20%"
value={price}
minValue={min_price}
maxValue={max_price}
unit="cr"
onChange={(value) =>
act('change_price', {
value: value,
})
}
/>
</Stack.Item>
<Stack.Divider />
{!!loaded_icon && (
<Stack.Item>
<Section align="center">
<Image
m={1}
src={`data:image/jpeg;base64,${loaded_icon}`}
height="96px"
width="96px"
/>
</Section>
</Stack.Item>
)}
<Stack.Divider />
<Stack.Item grow>
<TextArea
height="90%"
value={desc}
placeholder="Insert a description (or don't)"
onChange={(e, value) =>
act('change_desc', {
value: value,
})
}
/>
</Stack.Item>
<Stack.Divider />
<Stack.Item>
<Button.Confirm
fluid
icon="truck-arrow-right"
content="Place on Market"
onClick={() => act('place_on_market')}
/>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};