Skip to content

Commit fb8c3a0

Browse files
Marketplace in hybrid
1 parent 53af3f1 commit fb8c3a0

4 files changed

Lines changed: 429 additions & 3 deletions

File tree

CafeCosmosHybrid/Pages/Game.razor

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,11 @@
292292
}
293293
</MudTabPanel>
294294

295-
<MudTabPanel Icon="@Icons.Material.Filled.Shop" ToolTip="Catalogue">
295+
<MudTabPanel Icon="@Icons.Material.Filled.Shop" ToolTip="Marketplace">
296296
@if (GameViewModel.IsLoaded())
297297
{
298298
<MudGrid Class="ml-5 pt-0 pl-0 pr-0 mr-0">
299-
<Catalogue GameViewModel="GameViewModel"></Catalogue>
299+
<Marketplace GameViewModel="GameViewModel"></Marketplace>
300300
</MudGrid>
301301
}
302302
</MudTabPanel>
@@ -385,12 +385,18 @@
385385

386386
public async Task ActiveTabPanelChanged(int activeIndex)
387387
{
388+
388389
mudTabsActiveIndex = activeIndex;
389390
if (activeIndex == 3) // scoreboard navigation refresh
390391
{
391392
await GameViewModel.RefreshLeaderBoardAsync();
392393
}
393394

395+
if(activeIndex == 2){
396+
await GameViewModel.RefreshMarketPlaceListingsAsync();
397+
398+
}
399+
394400
if (activeIndex == 0)
395401
{
396402
try
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
@using CafeCosmosBlazor.ViewModel;
2+
@using System.Numerics
3+
@using VisionsContracts.Items;
4+
@using VisionsContracts.Items.Model;
5+
@using VisionsContracts.Land.Systems.MarketplaceSystem.Model;
6+
@using VisionsContracts.LandNFTs.ContractDefinition
7+
@using VisionsContracts.Land.Systems.MarketplaceSystem.Exceptions;
8+
@using VisionsContracts.PlayerBalancePurchasing.Exceptions
9+
10+
<MudPaper Class="mt-5">
11+
<MudCard Style="width:800px">
12+
<MudCardContent>
13+
<MudText Typo="Typo.h6">Find marketplace item to purchase</MudText>
14+
<MudStack Row="true" AlignItems="AlignItems.Center">
15+
@if (foundItem != null)
16+
{
17+
<MudAvatar Color="Color.Transparent" Variant="Variant.Outlined" Image="@GetImage(foundItem.Item)" Size="Size.Medium" />
18+
}
19+
<MudAutocomplete T="SearchItemMarketplace" MaxItems="1000"
20+
Label="Enter the name of the item to find the listing" @bind-Value="foundItem"
21+
SearchFunc="@SearchItemByName" ToStringFunc="@(e=> e==null?null : $"{e.Item.Name}, (Inventory: {e.InventoryQuantity})")">
22+
23+
<ItemTemplate Context="e">
24+
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="5">
25+
<MudAvatar Color="Color.Transparent" Variant="Variant.Outlined" Image="@GetImage(e.Item)" Size="Size.Medium" />
26+
<MudText Typo="Typo.body2">
27+
@($"{e.Item.Name}, (Inventory: {e.InventoryQuantity})")
28+
</MudText>
29+
</MudStack>
30+
</ItemTemplate>
31+
32+
33+
</MudAutocomplete>
34+
</MudStack>
35+
</MudCardContent>
36+
<MudCardActions>
37+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="SelectFoundItem">Select</MudButton>
38+
</MudCardActions>
39+
</MudCard>
40+
41+
42+
@if (selectedItem != null)
43+
{
44+
<MudTabs Elevation="4" Rounded="true" Centered="true" Color="@Color.Primary">
45+
<MudTabPanel Text="For sale" >
46+
<MudStack Row="true" Spacing="10">
47+
<MudCard Class="mt-3">
48+
<MudCardContent>
49+
<MudStack Row="true" Spacing="5">
50+
<MudText Typo="Typo.h5">Marketplace listings for @selectedItem.Name</MudText> <MudAvatar Color="Color.Transparent" Variant="Variant.Outlined" Image="@GetImage(selectedItem)" Size="Size.Medium" />
51+
</MudStack>
52+
<MudText Typo="Typo.body2">Available in Inventory: @GameViewModel.GetInventoryItemsFromPlayerLocalState().FirstOrDefault(x => x.ItemId == GetId(selectedItem))?.Count</MudText>
53+
54+
<table width="100%">
55+
56+
@foreach(var marketplaceListing in GetMarketPlaceListingsForSelectedItem())
57+
{
58+
<tr>
59+
<td>
60+
<MudStack Row="true" AlignItems="AlignItems.Center">
61+
<MudAvatar Color="Color.Transparent" Variant="Variant.Outlined" Image="@GetImage(selectedItem)" Size="Size.Medium" />
62+
<MudStack Spacing="0" Row="false" AlignItems="AlignItems.Start">
63+
<MudText Typo="Typo.body2">
64+
@GetLandName(marketplaceListing.Owner)
65+
</MudText>
66+
<MudText Typo="Typo.body2">
67+
<i>Price per unit: @marketplaceListing.UnitPriceInMainUnit</i>
68+
</MudText>
69+
<MudText Typo="Typo.body2">
70+
<i>Quantity for sale: @marketplaceListing.Quantity</i>
71+
</MudText>
72+
</MudStack>
73+
</MudStack>
74+
</td>
75+
76+
<td>
77+
@if (marketplaceListing.Owner.ToString() != GameViewModel.GetLandId())
78+
{
79+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="@(() => SelectListing(marketplaceListing))">Purchase</MudButton>
80+
}
81+
else
82+
{
83+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="@(() => SelectListing(marketplaceListing))">Edit listing</MudButton>
84+
}
85+
</td>
86+
87+
</tr>
88+
}
89+
</table>
90+
</MudCardContent>
91+
</MudCard>
92+
@if (selectedMarketplaceListing != null)
93+
{
94+
<MudCard Class="mt-16">
95+
<MudCardContent>
96+
97+
@if (IsSelectedListingOwner())
98+
{
99+
<MudText Typo="Typo.h5">Edit listing for @selectedItem.Name</MudText>
100+
<MudTextField Label="Price per unit" @bind-Value="editingListingPrice" Type="InputType.Number"> </MudTextField>
101+
<MudTextField Label="Quantity" @bind-Value="editingListingQuantity" Type="InputType.Number"> </MudTextField>
102+
103+
}
104+
else
105+
{
106+
<MudText Typo="Typo.h5">Purchase from Marketplace @selectedItem.Name</MudText>
107+
<MudText Typo="Typo.body2">Owner: @GetLandName(selectedMarketplaceListing.Owner), Price: @selectedMarketplaceListing.UnitPriceInMainUnit Available: @selectedMarketplaceListing.Quantity</MudText>
108+
<MudTextField Label="Quantity" @bind-Value="purchaseQuantity" Type="InputType.Number"> </MudTextField>
109+
}
110+
111+
</MudCardContent>
112+
<MudCardActions>
113+
114+
@if (IsSelectedListingOwner())
115+
{
116+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="EditListingAsync">Save</MudButton>
117+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="CancelListingAsync">Remove listing</MudButton>
118+
119+
}
120+
else
121+
{
122+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="PurchaseItemAsync">Purchase Item</MudButton>
123+
}
124+
125+
</MudCardActions>
126+
</MudCard>
127+
}
128+
</MudStack>
129+
</MudTabPanel>
130+
<MudTabPanel Text="Sell" >
131+
@if (GameViewModel.GetInventoryItemsFromPlayerLocalState().FirstOrDefault(x => x.ItemId == GetId(selectedItem)).Count > 0)
132+
{
133+
<MudCard Class="mt-3">
134+
<MudCardContent>
135+
<MudStack Row="true" Spacing="5">
136+
<MudText Typo="Typo.h5">Sell your @selectedItem.Name</MudText> <MudAvatar Color="Color.Transparent" Variant="Variant.Outlined" Image="@GetImage(selectedItem)" Size="Size.Medium" />
137+
</MudStack>
138+
<MudText Typo="Typo.body2">Available in Inventory: @GameViewModel.GetInventoryItemsFromPlayerLocalState().FirstOrDefault(x => x.ItemId == GetId(selectedItem))?.Count</MudText>
139+
<MudTextField Label="Price per unit" @bind-Value="newListingPrice" Type="InputType.Number"> </MudTextField>
140+
<MudTextField Label="Quantity" @bind-Value="newListingQuantity" Type="InputType.Number"> </MudTextField>
141+
</MudCardContent>
142+
<MudCardActions>
143+
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="CreateListingAsync">Create new listing</MudButton>
144+
</MudCardActions>
145+
</MudCard>
146+
}
147+
else
148+
{
149+
<MudCard Class="mt-16">
150+
<MudCardContent>
151+
152+
<MudText Typo="Typo.h5">No items in your inventory to sell @selectedItem.Name</MudText>
153+
</MudCardContent>
154+
</MudCard>
155+
}
156+
</MudTabPanel>
157+
</MudTabs>
158+
159+
160+
}
161+
</MudPaper>
162+
@if(!string.IsNullOrEmpty(errorMessage))
163+
{
164+
<MudAlert Class="mt-5" Severity="Severity.Error" Square="true" ShowCloseIcon="true" CloseIconClicked="(() => errorMessage = String.Empty)">@errorMessage</MudAlert>
165+
}
166+
167+
@code {
168+
[Parameter] public GameViewModel GameViewModel { get; set; }
169+
170+
171+
private SearchItemMarketplace foundItem;
172+
private Item selectedItem;
173+
private MarketPlaceListing selectedMarketplaceListing;
174+
175+
private decimal editingListingPrice;
176+
private int editingListingQuantity;
177+
178+
private decimal newListingPrice;
179+
private int newListingQuantity;
180+
181+
private int purchaseQuantity;
182+
183+
184+
185+
186+
private string errorMessage;
187+
188+
private async Task<IEnumerable<SearchItemMarketplace>> SearchItemByName(string value)
189+
{
190+
var items = GetAllSearchItemsForMarketplace();
191+
if (string.IsNullOrEmpty(value)) return items;
192+
193+
return items.Where(x => x.Item.Name.ToLower().Contains(value.ToLower()));
194+
}
195+
196+
private List<SearchItemMarketplace> GetAllSearchItemsForMarketplace()
197+
{
198+
var returnList = new List<SearchItemMarketplace>();
199+
var userInventory = GameViewModel.GetInventoryItemsFromPlayerLocalState();
200+
var allThemeItems = ThemeService.GetAllItems();
201+
var inventoryItems = DefaultItems.GetAllInventoryItems().Where(x => !allThemeItems.Any(y => y.Id == x.Id));
202+
foreach(var inventoryItem in inventoryItems)
203+
{
204+
var userInventoryItem = userInventory.FirstOrDefault(x => x.ItemId == inventoryItem.Id);
205+
206+
var searchItem = new SearchItemMarketplace()
207+
{
208+
Item = inventoryItem,
209+
InventoryQuantity = (int)userInventoryItem?.Count
210+
};
211+
returnList.Add(searchItem);
212+
}
213+
214+
return returnList;
215+
}
216+
217+
private class SearchItemMarketplace
218+
{
219+
public Item Item { get; set; }
220+
public int Quantity { get; set; }
221+
public int InventoryQuantity { get; set; }
222+
223+
}
224+
225+
226+
227+
public bool IsSelectedListingOwner()
228+
{
229+
if (selectedMarketplaceListing == null) return false;
230+
return selectedMarketplaceListing.Owner.ToString() == GameViewModel.GetLandId();
231+
}
232+
233+
public string GetLandName(BigInteger landId)
234+
{
235+
if (GameViewModel.LandNames == null) return "Unknown";
236+
var land = GameViewModel.LandNames.FirstOrDefault(x => x.LandId == landId);
237+
if (land == null) return "Unknown";
238+
return land.Name;
239+
}
240+
241+
public IEnumerable<MarketPlaceListing> GetMarketPlaceListingsForSelectedItem()
242+
{
243+
if (GameViewModel.MarketPlaceListings == null) return new List<MarketPlaceListing>();
244+
return GameViewModel.MarketPlaceListings.Where(x => x.ItemId == GetId(selectedItem)).OrderBy(x => x.UnitPriceInMainUnit);
245+
}
246+
247+
public async Task SelectFoundItem()
248+
{
249+
selectedItem = foundItem.Item;
250+
foundItem = null;
251+
selectedMarketplaceListing = null;
252+
await GameViewModel.RefreshMarketPlaceListingsAsync();
253+
}
254+
255+
public async Task EditListingAsync()
256+
{
257+
await GameViewModel.EditMarketPlaceListingAsync(selectedMarketplaceListing.ListingId, editingListingPrice, editingListingQuantity);
258+
await GameViewModel.RefreshMarketPlaceListingsAsync();
259+
selectedMarketplaceListing = null;
260+
editingListingPrice = 0;
261+
editingListingQuantity = 0;
262+
}
263+
264+
public void SelectListing(MarketPlaceListing listing)
265+
{
266+
this.selectedMarketplaceListing = listing;
267+
if (IsSelectedListingOwner())
268+
{
269+
editingListingPrice = listing.UnitPriceInMainUnit;
270+
editingListingQuantity = (int) listing.Quantity;
271+
}
272+
else
273+
{
274+
purchaseQuantity = 0;
275+
}
276+
}
277+
278+
public async Task CancelListingAsync()
279+
{
280+
await GameViewModel.CancelMarketPlaceListingAsync(selectedMarketplaceListing.ListingId);
281+
await GameViewModel.RefreshMarketPlaceListingsAsync();
282+
selectedMarketplaceListing = null;
283+
editingListingPrice = 0;
284+
editingListingQuantity = 0;
285+
}
286+
287+
public async Task CreateListingAsync()
288+
{
289+
await GameViewModel.CreateMarketPlaceListingAsync(selectedItem.Id, newListingQuantity, newListingPrice);
290+
await GameViewModel.RefreshMarketPlaceListingsAsync();
291+
newListingPrice = 0;
292+
newListingQuantity = 0;
293+
}
294+
295+
public async Task PurchaseItemAsync()
296+
{
297+
errorMessage = null;
298+
299+
try
300+
{
301+
await GameViewModel.PurchaseMarketplaceListing(selectedMarketplaceListing.ListingId, purchaseQuantity);
302+
await GameViewModel.RefreshMarketPlaceListingsAsync(); ;
303+
selectedMarketplaceListing = null;
304+
purchaseQuantity = 0;
305+
}
306+
catch (InsufficientQuantityInMarketplaceListingToPurchaseException ex)
307+
{
308+
errorMessage = ex.Message;
309+
}
310+
catch (InsufficientBalanceToPurchaseException ex)
311+
{
312+
errorMessage = ex.Message;
313+
}
314+
catch (Exception ex)
315+
{
316+
errorMessage = ex.Message;
317+
}
318+
}
319+
public async Task SelectItemAsync(Item item)
320+
{
321+
errorMessage = null;
322+
if (item != null)
323+
{
324+
await GameViewModel.RefreshMarketPlaceListingsAsync();
325+
this.selectedItem = item;
326+
327+
}
328+
else
329+
{
330+
this.errorMessage = "Item not found";
331+
}
332+
}
333+
334+
335+
336+
private int GetId(Item item)
337+
{
338+
if (item == null) return 0;
339+
return item.Id;
340+
}
341+
342+
343+
private string GetImage(Item item)
344+
{
345+
var image = ItemImages.AllImages.FirstOrDefault(x => x.Item.Id == item.Id);
346+
if (image != null)
347+
{
348+
return "images/icons/" + image.Image;
349+
}
350+
return null;
351+
}
352+
353+
354+
355+
356+
357+
}

0 commit comments

Comments
 (0)