merge to master

This commit is contained in:
Loretta 2025-08-30 13:04:06 +02:00
commit 08c2ed18cd
107 changed files with 4382 additions and 755 deletions

View File

@ -67,10 +67,10 @@ public static class TiamConstClient
};
#if RELEASE
public static string SystemEmailAddress = "system@touriam.com";
public static string SystemEmailAddress = "test@touriam.com";
public static LogLevel DefaultLogLevelClient = LogLevel.Debug;
#else
public static string SystemEmailAddress = "system@anataworld.com";
public static string SystemEmailAddress = "test@touriam.com";
public static LogLevel DefaultLogLevelClient = LogLevel.Detail;
#endif
}

View File

@ -3,6 +3,6 @@
public enum SeatNumberPriceType : byte
{
Price1SeatNum = 0,
Price2SeatNum = 4,
Price3SeatNum = 8,
Price2SeatNum = 5,
Price3SeatNum = 7,
}

View File

@ -14,7 +14,7 @@ using AyCode.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
using TIAM.Entities.ServiceProviders;
using TIAM.Entities.Addresses;
using DevExpress.Pdf.Native.BouncyCastle.Asn1.Ocsp;
//using DevExpress.Pdf.Native.BouncyCastle.Asn1.Ocsp;
namespace TIAM.Database.Test
{

View File

@ -23,10 +23,10 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />

View File

@ -34,6 +34,7 @@ using AyCode.Interfaces.Entities;
using TIAM.Models;
using TIAM.Models.Dtos.Users;
using TIAM.Models.PageViewModels;
using EmailMessage = TIAM.Entities.Emails.EmailMessage;
namespace TIAM.Database.DataLayers.Admins
{

View File

@ -10,6 +10,7 @@ using TIAM.Entities.ServiceProviders;
using TIAM.Entities.Users;
using TIAM.Models;
using TIAM.Models.Dtos.Users;
using EmailMessage = TIAM.Entities.Emails.EmailMessage;
namespace TIAM.Database.DataLayers.Users
{

View File

@ -10,11 +10,32 @@ namespace TIAM.Database.DbSets.Transfers;
public static class TransferToDriverDbSetExtensions
{
#region TransferToDriver
public static TransferToDriver? GetTransferToDriverById(this ITransferToDriverDbSet ctx, Guid transferToDriverId, bool autoInclude = true)
=> ctx.TransferToDrivers.FirstOrDefault(x => x.Id == transferToDriverId);
=> ctx.TransferToDrivers
.Where(x => x.Id == transferToDriverId)
.Include(x => x.UserProductMapping.User.Products).ThenInclude(x => x.UserProductMappings)
.Include(x => x.Car.UserProductMapping.Product.ServiceProvider).ThenInclude(x => x.Products)
.Include(x => x.UserProductMapping.User.Profile.Address)
.Include(x => x.Transfer)
.FirstOrDefault(x => x.Id == transferToDriverId);
public static IQueryable<TransferToDriver> GetTransferToDriversByTransferId(this ITransferToDriverDbSet ctx, Guid transferId, bool autoInclude = true)
=> ctx.TransferToDrivers.Where(x => x.TransferId == transferId);
=> ctx.TransferToDrivers
.Where(x => x.TransferId == transferId)
.Include(x => x.Car.UserProductMapping.Product.ServiceProvider).ThenInclude(x => x.Products)
.Include(x => x.UserProductMapping.User.Profile.Address)
.Include(x => x.Transfer);
//.Include(x => x.UserProductMapping.User.Products).ThenInclude(x => x.UserProductMappings)
//.Include(x => x.Car.UserProductMapping.Product.ServiceProvider).ThenInclude(x => x.Products)
//.Include(x => x.UserProductMapping.User.Profile.Address)
//.Include(x => x.Transfer);
//.Include(x => x.UserProductMapping.User.Products).ThenInclude(x => x.UserProductMappings).ThenInclude(x => x.User.Profile.Address)
//.Include(x => x.Car.UserProductMapping.Product.ServiceProvider).ThenInclude(x => x.Products)
//.Include(x => x.UserProductMapping.User.Profile.Address)
//.Include(x => x.Transfer);
public static IQueryable<TransferToDriver> GetTransferToDriversByUpmId(this ITransferToDriverDbSet ctx, Guid upmId, bool autoInclude = true)
=> ctx.TransferToDrivers.Where(x => x.UserProductMappingId == upmId);

View File

@ -7,11 +7,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Data" Version="24.1.3" />
<PackageReference Include="DevExpress.Data" Version="24.2.3" />
<PackageReference Include="MessagePack.Annotations" Version="2.5.187" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

View File

@ -0,0 +1,68 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Data" Version="24.2.3" />
<PackageReference Include="MessagePack.Annotations" Version="2.5.187" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="DataLayers\DTOs\" />
<Folder Include="DataLayers\Permissions\" />
<Folder Include="DataLayers\Products\" />
<Folder Include="DbSets\Addresses\" />
<Folder Include="Extensions\" />
<Folder Include="ModelBuilders\Emails\" />
<Folder Include="ModelBuilders\Profiles\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TIAM.Core\TIAM.Core.csproj" />
<ProjectReference Include="..\TIAM.Entities.Server\TIAM.Entities.Server.csproj" />
<ProjectReference Include="..\TIAM.Entities\TIAM.Entities.csproj" />
<ProjectReference Include="..\TIAM.Models\TIAM.Models.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="AyCode.Core">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Core.dll</HintPath>
</Reference>
<Reference Include="AyCode.Core.Server">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Core.Server.dll</HintPath>
</Reference>
<Reference Include="AyCode.Database">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Database.dll</HintPath>
</Reference>
<Reference Include="AyCode.Entities">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Entities.dll</HintPath>
</Reference>
<Reference Include="AyCode.Entities.Server">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Entities.Server.dll</HintPath>
</Reference>
<Reference Include="AyCode.Interfaces">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Interfaces.dll</HintPath>
</Reference>
<Reference Include="AyCode.Interfaces.Server">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Interfaces.Server.dll</HintPath>
</Reference>
<Reference Include="AyCode.Models">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Models.dll</HintPath>
</Reference>
<Reference Include="AyCode.Models.Server">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Models.Server.dll</HintPath>
</Reference>
<Reference Include="AyCode.Utils">
<HintPath>..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Utils.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -6,6 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Data" Version="24.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TIAM.Core\TIAM.Core.csproj" />
<ProjectReference Include="..\TIAM.Entities.Server\TIAM.Entities.Server.csproj" />

View File

@ -1,6 +1,7 @@
using AyCode.Blazor.Models.ViewModels;
using TIAM.Entities.Emails;
using TIAM.Models.PageViewModels;
using EmailMessage = TIAM.Entities.Emails.EmailMessage;
namespace TIAM.Models;

View File

@ -12,6 +12,10 @@
<Folder Include="GridViewModels\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Data" Version="24.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Aycode.Blazor\AyCode.Blazor.Components\AyCode.Blazor.Components.csproj" />
<ProjectReference Include="..\..\Aycode.Blazor\AyCode.Blazor.Models\AyCode.Blazor.Models.csproj" />

View File

@ -1,7 +1,6 @@
{
"ConnectionStrings": {
"DeveloperDbConnection":
"Data Source=185.51.190.197;Initial Catalog=TIAM_DEV;Trusted_Connection=false;Encrypt=false;TrustServerCertificate=True;Connect Timeout=200;User ID=Anata_Development_Team;Password=v6f_?xNfg9N1;MultipleActiveResultSets=true"
"DeveloperDbConnection": "Data Source=195.26.231.218;Initial Catalog=TIAM_DEV;Trusted_Connection=false;Encrypt=false;TrustServerCertificate=True;Connect Timeout=200;User ID=sa;Password=v6f_?xNfg9N1;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {

View File

@ -1,4 +1,5 @@
using System.Net;
using System.Net.Mail;
using AyCode.Core.Helpers;
using AyCode.Models.Enums;
using Microsoft.Extensions.Configuration;
@ -13,6 +14,11 @@ namespace TIAM.Services.Server
{
public class MessageSenderService(IConfiguration configuration, AdminDal adminDal) : IMessageSenderService
{
private readonly string smtpHost = "smtp.rackhost.hu";
private readonly int smtpPort = 587; // Change if needed
private readonly string smtpUser = "system@touriam.com";
private readonly string smtpPass = "Villany1";
public async Task<string> SendMessageAsync(EmailMessage message, int messageType)
{
var result = "";
@ -24,7 +30,8 @@ namespace TIAM.Services.Server
//var subject = emailMessage.Subject;
//adminDal.AddEmailMessageAsync(message).Forget();
result = (await SendMailWithSendgrid(message)).ToString(); //?? HttpStatusCode.BadRequest.ToString();
//result = (await SendMailWithSendgrid(message)).ToString(); //?? HttpStatusCode.BadRequest.ToString();
result = (await SendMailWithSmtp(message)).ToString(); //?? HttpStatusCode.BadRequest.ToString();
break;
case (int)MessageTypesEnum.sms:
//await SendSmsWithTwilio(message.Message);
@ -159,6 +166,197 @@ namespace TIAM.Services.Server
}
//public async Task<HttpStatusCode> SendMailWithSmtp(EmailMessage message)
//{
// Console.WriteLine($"Sender: {message.SenderId}");
// Console.WriteLine($"Message: {message.Text}");
// if (message.Recipients == null || !message.Recipients.Any())
// {
// return HttpStatusCode.BadRequest;
// }
// using (var smtpClient = new SmtpClient(smtpHost, smtpPort))
// {
// smtpClient.Credentials = new NetworkCredential(smtpUser, smtpPass);
// smtpClient.EnableSsl = true;
// var fromAddress = new MailAddress(smtpUser, "Your Mail Service");
// List<Task> sendTasks = new List<Task>();
// foreach (var recipient in message.Recipients)
// {
// var toAddress = new MailAddress(recipient.EmailAddress);
// var mailMessage = new MailMessage(fromAddress, toAddress)
// {
// Subject = message.Subject,
// Body = message.Text,
// IsBodyHtml = true
// };
// //sendTasks.Add(Task.Run(() => smtpClient.SendMailAsync(mailMessage)));
// sendTasks.Add(smtpClient.SendMailAsync(mailMessage));
// }
// try
// {
// await Task.WhenAll(sendTasks);
// Console.WriteLine("All emails sent successfully");
// return HttpStatusCode.OK;
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Failed to send emails: {ex.Message}");
// return HttpStatusCode.InternalServerError;
// }
// }
//}
//public async Task<HttpStatusCode> SendMailWithSmtp(EmailMessage message)
//{
// Console.WriteLine($"Sender: {message.SenderId}");
// Console.WriteLine($"Message: {message.Text}");
// if (message.Recipients == null || !message.Recipients.Any())
// {
// return HttpStatusCode.BadRequest;
// }
// List<Task> sendTasks = new List<Task>();
// foreach (var recipient in message.Recipients)
// {
// var smtpClient = new SmtpClient(smtpHost, smtpPort)
// {
// Credentials = new NetworkCredential(smtpUser, smtpPass),
// EnableSsl = true,
// TargetName = $"SMTPS/{smtpHost}"
// };
// var fromAddress = new MailAddress(smtpUser, "Your Mail Service");
// var toAddress = new MailAddress(recipient.EmailAddress);
// var mailMessage = new MailMessage(fromAddress, toAddress)
// {
// Subject = message.Subject,
// Body = message.Text,
// IsBodyHtml = true
// };
// sendTasks.Add(Task.Run(async () =>
// {
// try
// {
// await smtpClient.SendMailAsync(mailMessage);
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Failed to send email to {recipient.EmailAddress}: {ex.Message}");
// throw; // Ensure exceptions bubble up
// }
// finally
// {
// smtpClient.Dispose();
// }
// }));
// }
// var timeoutTask = Task.Delay(TimeSpan.FromSeconds(30)); // Prevent indefinite waiting
// var allTasks = Task.WhenAll(sendTasks);
// var completedTask = await Task.WhenAny(allTasks, timeoutTask);
// if (completedTask == timeoutTask)
// {
// Console.WriteLine("Email sending timed out.");
// return HttpStatusCode.RequestTimeout;
// }
// try
// {
// await allTasks; // Rethrow if there were failures
// Console.WriteLine("All emails sent successfully");
// return HttpStatusCode.OK;
// }
// catch (Exception)
// {
// Console.WriteLine("Some emails failed to send");
// return HttpStatusCode.InternalServerError;
// }
//}
public async Task<HttpStatusCode> SendMailWithSmtp(EmailMessage message)
{
Console.WriteLine($"Sender: {message.SenderId}");
Console.WriteLine($"Message: {message.Text}");
if (message.Recipients == null || !message.Recipients.Any())
{
return HttpStatusCode.BadRequest;
}
List<Task> sendTasks = new List<Task>();
foreach (var recipient in message.Recipients)
{
sendTasks.Add(Task.Run(async () =>
{
try
{
using (var smtpClient = new SmtpClient(smtpHost, smtpPort))
{
smtpClient.Credentials = new NetworkCredential(smtpUser, smtpPass);
smtpClient.EnableSsl = true; // Try false for port 587
smtpClient.TargetName = $"SMTPS/{smtpHost}";
var fromAddress = new MailAddress(smtpUser, "Your Mail Service");
var toAddress = new MailAddress(recipient.EmailAddress);
var mailMessage = new MailMessage(fromAddress, toAddress)
{
Subject = message.Subject,
Body = message.Text,
IsBodyHtml = true
};
await smtpClient.SendMailAsync(mailMessage);
}
}
catch (Exception ex)
{
Console.WriteLine($"Failed to send email to {recipient.EmailAddress}: {ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"Inner Exception: {ex.InnerException.Message}");
}
throw;
}
}));
}
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(30)); // Prevent indefinite waiting
var allTasks = Task.WhenAll(sendTasks);
var completedTask = await Task.WhenAny(allTasks, timeoutTask);
if (completedTask == timeoutTask)
{
Console.WriteLine("Email sending timed out.");
return HttpStatusCode.RequestTimeout;
}
try
{
await allTasks; // Rethrow if there were failures
Console.WriteLine("All emails sent successfully");
return HttpStatusCode.OK;
}
catch (Exception)
{
Console.WriteLine("Some emails failed to send");
return HttpStatusCode.InternalServerError;
}
}
public string GenerateWelcomeEmail(string userName, string activationCode)
{
string template = EmailTemplateHelper.GetTemplate(TiamConstClient.WelcomeEmailTemplateName);

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>D:\REPOS\TOURIAM_PUBLISH</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
</PropertyGroup>
</Project>

View File

@ -30,6 +30,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Blazor" Version="24.2.3" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.10" />
<PackageReference Include="SendGrid" Version="9.29.3" />
</ItemGroup>

View File

@ -62,7 +62,7 @@ namespace TIAM.Services.Server
};
}
public double GetCommission(Guid productId, double Price, TransferDestination to)
public double GetCommission(Guid productId, double price, TransferDestination to)
{
//check if Destination has a custom commissionRate by productId
double commissionRate = 0;
@ -92,7 +92,7 @@ namespace TIAM.Services.Server
}
}
commission = GetCommission(Price, commissionRate);
commission = GetCommission(price, commissionRate);
return commission;
}

View File

@ -6,6 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Data" Version="24.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TIAM.Core\TIAM.Core.csproj" />
<ProjectReference Include="..\TIAM.Entities\TIAM.Entities.csproj" />

View File

@ -53,7 +53,7 @@
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" />
<PackageReference Include="SkiaSharp" Version="2.88.8" />
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.88.8" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" VersionOverride="7.0.1" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" VersionOverride="7.0.1" Version="9.0.3" />
</ItemGroup>
<ItemGroup>

View File

@ -2,8 +2,8 @@
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<IsFirstTimeProjectOpen>False</IsFirstTimeProjectOpen>
<ActiveDebugFramework>net8.0-windows10.0.19041.0</ActiveDebugFramework>
<ActiveDebugProfile>Windows Machine</ActiveDebugProfile>
<ActiveDebugFramework>net8.0-maccatalyst</ActiveDebugFramework>
<ActiveDebugProfile>Mac Catalyst</ActiveDebugProfile>
<SelectedPlatformGroup>PhysicalDevice</SelectedPlatformGroup>
<DefaultDevice>pixel_5_-_api_31</DefaultDevice>
</PropertyGroup>

View File

@ -384,6 +384,15 @@ namespace TIAM.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Who we are.
/// </summary>
public static string Index_WhoWeAre {
get {
return ResourceManager.GetString("Index.WhoWeAre", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Login.
/// </summary>
@ -456,6 +465,24 @@ namespace TIAM.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Book now!.
/// </summary>
public static string NavMenu_BookNow {
get {
return ResourceManager.GetString("NavMenu.BookNow", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Contact.
/// </summary>
public static string NavMenu_Contact {
get {
return ResourceManager.GetString("NavMenu.Contact", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Events.
/// </summary>
@ -465,6 +492,15 @@ namespace TIAM.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Explore the region.
/// </summary>
public static string NavMenu_ExploreTheRegion {
get {
return ResourceManager.GetString("NavMenu.ExploreTheRegion", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to FormulaOne.
/// </summary>
@ -483,6 +519,15 @@ namespace TIAM.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to How it works.
/// </summary>
public static string NavMenu_HowItWorks {
get {
return ResourceManager.GetString("NavMenu.HowItWorks", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Login.
/// </summary>
@ -510,6 +555,15 @@ namespace TIAM.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Signature ride packages.
/// </summary>
public static string NavMenu_SignatureRidePackages {
get {
return ResourceManager.GetString("NavMenu.SignatureRidePackages", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sign out.
/// </summary>

View File

@ -249,15 +249,27 @@
<data name="NavMenu.Admin" xml:space="preserve">
<value>Adminisztráció</value>
</data>
<data name="NavMenu.BookNow" xml:space="preserve">
<value>Foglalj most!</value>
</data>
<data name="NavMenu.Contact" xml:space="preserve">
<value>Kapcsolat</value>
</data>
<data name="NavMenu.Events" xml:space="preserve">
<value>Események</value>
</data>
<data name="NavMenu.ExploreTheRegion" xml:space="preserve">
<value>Fedezd fel a térséget</value>
</data>
<data name="NavMenu.FormulaOne" xml:space="preserve">
<value>Forma1</value>
</data>
<data name="NavMenu.Home" xml:space="preserve">
<value>Főoldal</value>
</data>
<data name="NavMenu.HowItWorks" xml:space="preserve">
<value>Miben más a TourIam</value>
</data>
<data name="NavMenu.Login" xml:space="preserve">
<value>Belépés</value>
</data>
@ -267,6 +279,9 @@
<data name="NavMenu.Settings" xml:space="preserve">
<value>Beállítások</value>
</data>
<data name="NavMenu.SignatureRidePackages" xml:space="preserve">
<value>Túrák</value>
</data>
<data name="NavMenu.SignOut" xml:space="preserve">
<value>Kijelentkezés</value>
</data>

View File

@ -225,6 +225,9 @@
<data name="Index.Transfer.Desc" xml:space="preserve">
<value>Do you need a lift? Book a transfer now!</value>
</data>
<data name="Index.WhoWeAre" xml:space="preserve">
<value>Who we are</value>
</data>
<data name="Login" xml:space="preserve">
<value>Login</value>
</data>
@ -249,15 +252,27 @@
<data name="NavMenu.Admin" xml:space="preserve">
<value>Admin</value>
</data>
<data name="NavMenu.BookNow" xml:space="preserve">
<value>Book now!</value>
</data>
<data name="NavMenu.Contact" xml:space="preserve">
<value>Contact</value>
</data>
<data name="NavMenu.Events" xml:space="preserve">
<value>Events</value>
</data>
<data name="NavMenu.ExploreTheRegion" xml:space="preserve">
<value>Explore the region</value>
</data>
<data name="NavMenu.FormulaOne" xml:space="preserve">
<value>FormulaOne</value>
</data>
<data name="NavMenu.Home" xml:space="preserve">
<value>Home</value>
</data>
<data name="NavMenu.HowItWorks" xml:space="preserve">
<value>How it works</value>
</data>
<data name="NavMenu.Login" xml:space="preserve">
<value>Login</value>
</data>
@ -267,6 +282,9 @@
<data name="NavMenu.Settings" xml:space="preserve">
<value>Settings</value>
</data>
<data name="NavMenu.SignatureRidePackages" xml:space="preserve">
<value>Signature ride packages</value>
</data>
<data name="NavMenu.SignOut" xml:space="preserve">
<value>Sign out</value>
</data>

View File

@ -19,10 +19,6 @@
At Tour I Am, we understand the importance of a seamless and comfortable journey for our valued customers. Whether you're arriving in Budapest for business or leisure, our dedicated team ensures that your transfer experience is hassle-free and enjoyable.
</p>
<p class="mb-4 pe-xl-12 ">

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,133 @@
@page "/blogpost/{PostId}"
@using TIAMSharedUI.Pages.Components
@using TIAMSharedUI.Shared
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI
@using TIAMWebApp.Shared.Application.Services
@inject HttpClient Http
@inject BlogService BlogService
<HeroSlider SliderItems="@sliders" PBottom="50px" Height="30vh"></HeroSlider>
@if (Content == null)
{
<p>Loading post...</p>
}
else
{
<div class="container">
<div class="card p-3" @onclick:stopPropagation>
@((MarkupString)Content)
</div>
@if (Tags?.Count > 0)
{
<p class="mt-3 text-muted small">
Tags: @string.Join(", ", Tags)
</p>
}
</div>
}
<CallToActionComponent></CallToActionComponent>
@code {
[Parameter]
public string PostId { get; set; }
private string? Content;
private string? Title;
private string? CoverImage;
private List<string>? Tags;
protected override async Task OnParametersSetAsync()
{
try
{
var post = await BlogService.GetPostByIdAsync(PostId);
if (post != null)
{
Title = post.Title;
CoverImage = post.CoverImage;
Tags = post.Tags;
// ✅ Extract fileId from DriveLink:
var fileId = ExtractGoogleDriveFileId(post.DriveLink);
if (!string.IsNullOrEmpty(fileId))
{
// string apiKey = "AIzaSyBLKx4XFpgX97sULTbtpyKA2Ca_ANrjxxs"; // your existing key
// // string downloadUrl = $"https://www.googleapis.com/drive/v3/files/{fileId}?alt=media&key={apiKey}";
// string downloadUrl = $"https://drive.google.com/uc?export=download&id={fileId}";
// Content = await Http.GetStringAsync(downloadUrl);
Content = null; // Optional: clear previous content while loading new
try
{
Content = await Http.GetStringAsync($"/api/blog/postcontent/{PostId}");
}
catch
{
Content = "<p class='text-danger'>Failed to load blog post.</p>";
}
}
else
{
Content = "<p class='text-danger'>Invalid Google Drive link in post metadata.</p>";
}
}
}
catch (Exception e)
{
Content = "<p class='text-danger'>Failed to load blog post. " + e.ToString()+ "</p>";
}
}
private string? ExtractGoogleDriveFileId(string driveLink)
{
try
{
// Works with typical Google Drive URLs
var match = System.Text.RegularExpressions.Regex.Match(driveLink, @"\/d\/([^\/]+)");
return match.Success ? match.Groups[1].Value : null;
}
catch
{
return null;
}
}
public List<HeroSliderItem> sliders = new()
{
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1551867633-194f125bddfa?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Explore Our Programs",
ButtonUrl= "/signature-ride-packages"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1549877452-9c387954fbc2?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Book now",
ButtonUrl= "/transfer"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "",
ImageUrl = "https://images.unsplash.com/photo-1507622560124-621e26755fb8?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "",
ButtonUrl= ""
}
};
}

View File

@ -1,4 +1,5 @@
@using TIAMWebApp.Shared.Application.Models.PageModels;
@using DevExpress.Blazor
@using TIAMWebApp.Shared.Application.Models.PageModels;
@using TIAMWebApp.Shared.Application.Models;
@using TIAMWebApp.Shared.Application.Interfaces;
@inject ISessionServiceClient sessionService;

View File

@ -1,10 +1,10 @@
<div class="container text-center py-4 py-md-6 rounded-3">
<div class="lc-block card border-0 text-center rounded p-4 p-lg-6" style="background:url(https://cdn.livecanvas.com/media/backgrounds/fffuelco/ffflux.svg) center / cover no-repeat;">
<div class="container-fluid text-center pt-4 py-md-6">
<div class="lc-block card border-0 text-center py-5" style="background: #4c327b; background-position: center; background-size: cover;">
<div class="row card-body mb-3 mb-lg-4">
<div class="col-xl-11 col-xxl-9 mx-auto">
<div class="lc-block mb-4">
<div editable="rich">
<p class="text-white">JOIN OUR COMMUNITY</p>
<p class="text-white">READY TO GO?</p>
</div>
</div>
<div class="lc-block">
@ -14,7 +14,7 @@
</div>
</div>
</div>
<div class="lc-block"><a class="btn btn-primary btn-lg" href="#" role="button">Get Started</a></div>
<div class="lc-block"><a class="btn btn-primary btn-lg" href="#" role="button">Book now!</a></div>
</div>
</div>

View File

@ -0,0 +1,55 @@
@using System.Text
@using AyCode.Core.Helpers
@using TIAM.Entities.Transfers
@using TIAM.Services
@using TIAMWebApp.Shared.Application.Services
@inject AdminSignalRClient _adminSignalRClient;
<p>@DriverName</p>
@code {
[Parameter] public Guid TransferId { get; set; }
private string DriverName = "";
protected override void OnParametersSet()
{
_adminSignalRClient.GetByIdAsync<List<TransferToDriver>>(SignalRTags.GetTransferDriversByTransferId, x =>
{
//await Task.Delay(1);
var keyItemTransferToDriver = x.ResponseData;
if (keyItemTransferToDriver != null && keyItemTransferToDriver.Count > 0)
{
foreach (var driver in keyItemTransferToDriver)
{
if (driver != null && driver.UserProductMapping != null)
{
if (driver.UserProductMapping.User != null)
{
if (driver.UserProductMapping.User.Profile != null)
{
if (!string.IsNullOrEmpty(driver.UserProductMapping.User.Profile.Name))
{
DriverName = driver.UserProductMapping.User.Profile.Name;
}
else
{
DriverName = driver.LicencePlate;
}
}
}
}
}
}
else
{
DriverName = "No driver assigned yet";
}
return Task.CompletedTask;
}, TransferId).Forget();
}
}

View File

@ -1,4 +1,5 @@
@using TIAMWebApp.Shared.Application.Models;
@using DevExpress.Blazor
@using TIAMWebApp.Shared.Application.Models;
@using TIAMWebApp.Shared.Application.Interfaces;
@inject ISessionServiceClient sessionService;

View File

@ -38,15 +38,15 @@
</div>
<DxPopup CssClass="popup-demo-events"
@bind-Visible="@_popupVisible"
ShowFooter="true"
CloseOnEscape="true"
CloseOnOutsideClick="false"
ShowCloseButton="false"
HeaderText="MessageBox"
Closing="EmailPopupClosing"
Closed="EmailPopupClosed"
SizeMode="SizeMode.Large">
@bind-Visible="@_popupVisible"
ShowFooter="true"
CloseOnEscape="true"
CloseOnOutsideClick="false"
ShowCloseButton="false"
HeaderText="MessageBox"
Closing="EmailPopupClosing"
Closed="EmailPopupClosed"
SizeMode="SizeMode.Large">
<BodyContentTemplate>
@{
if(showResultMessage)
@ -56,11 +56,11 @@
else
{
<DynamicEditForm Data=@_messageWizardModel
OnSubmit="SubmitForm"
TitleString="New message"
ButtonTextString="Send message"
isEditing="true"
IgnoreReflection=@IgnoreList></DynamicEditForm>
OnSubmit="SubmitForm"
TitleString="New message"
ButtonTextString="Send message"
isEditing="true"
IgnoreReflection=@IgnoreList></DynamicEditForm>
}
}
@ -92,8 +92,8 @@
{
<div class="text-center m-5">
<DxWaitIndicator Visible="true"
CssClass="m-auto"
AnimationType="WaitIndicatorAnimationType.Spin" />
CssClass="m-auto"
AnimationType="WaitIndicatorAnimationType.Spin" />
</div>
}
@ -155,7 +155,7 @@ else
<hr />
<p class="text-muted">Status on: <span class="text-body">@DateTime.Now.ToString("hh:mm tt"), @DateTime.Today.ToString("MMMM dd, yyyy")</span></p>
<h5 class="text-muted">@TransferStatusModel.GetStatusModel(_transfer.TransferStatusType);</h5>
<h5 class="text-muted">@TransferStatusModel.GetStatusModel(_transfer.TransferStatusType).StatusName;</h5>
</div>
</div>
@ -276,6 +276,7 @@ else
</div>
<div class="card-footer p-4">
<div class="d-flex justify-content-between">
<DxButton RenderStyle="ButtonRenderStyle.Warning" Click="@((e) => CancelTransferEventHandler(e, true))">Discard changes</DxButton>
<DxButton Click="@((e) => UpdateTransferEventHandler(e, true))">Save Changes</DxButton>
</div>
</div>
@ -292,7 +293,7 @@ else
<div style="margin-top: 10px; margin-bottom: 10px;">
<DxButton Click="() => SendMail(_transfer)" Text="Send a message" RenderStyle="ButtonRenderStyle.Primary" />
</div>
<MessageDetailGridComponent ContextId="transferId" IsSenderEmailVisible="false" IsMessageTextVisible="false"></MessageDetailGridComponent>
<MessageDetailGridComponent ContextId="_transfer.Id" GetAllMessageTag="SignalRTags.GetMessagesByContextId" IsSenderEmailVisible="false" IsMessageTextVisible="false"></MessageDetailGridComponent>
</DxTabPage>
</DxTabs>
</div>
@ -523,8 +524,14 @@ else
private async Task UpdateTransferEventHandler(MouseEventArgs e, bool shouldRedirect = false)
{
var result = await UpdateTransfer(shouldRedirect);
_editMode = false;
if (result != null && shouldRedirect)
navManager.NavigateTo("/mytransfers"); // Redirect to a list or another page after successful update
navManager.NavigateTo($"/mytransfers/{_transfer.Id}"); // Redirect to a list or another page after successful update
}
private async Task CancelTransferEventHandler(MouseEventArgs e, bool shouldRedirect = false)
{
_editMode = false;
}
private async Task<Transfer?> UpdateTransfer(bool shouldRedirect = false)

View File

@ -20,7 +20,7 @@
<div class="item" style="background-image: url(@item.ImageUrl);">
<div class="item-desc" style="height: 100%; background-color: rgba(0,0,0,0.3);">
<!--h3>item.Name</h3-->
<h3 class="card-title" style="margin-top: 80px;">@item.Name</h3>
<p>@item.DateAndTime</p>
@ -39,13 +39,6 @@
<a href="login">
</a>
</div>
</section>
@ -102,4 +95,4 @@
};
}
}

View File

@ -35,15 +35,15 @@
@_localizer["LoginTitleText"]
</div>
<div class="form-field">
<DxMaskedInput @bind-Value="@emailAddress"
Id="Email"
CssClass="form-control"
Mask="@EmailMask"
MaskMode="MaskMode.RegEx">
<DxRegExMaskProperties MaskAutoCompleteMode="@((MaskAutoCompleteMode)AutoCompleteMode)"
Placeholder="Placeholder"
PlaceholdersVisible="PlaceholderVisible" />
</DxMaskedInput>
<DxMaskedInput @bind-Value="@emailAddress"
Id="Email"
CssClass="form-control"
Mask="@EmailMask"
MaskMode="MaskMode.RegEx">
<DxRegExMaskProperties MaskAutoCompleteMode="@((MaskAutoCompleteMode)AutoCompleteMode)"
Placeholder="Placeholder"
PlaceholdersVisible="PlaceholderVisible" />
</DxMaskedInput>
</div>
<DxButton CssClass="btn btn-primary mt-3" Click="() => SendMail(emailAddress)">Send</DxButton>
<div class="text-center fs-6">
@ -88,6 +88,6 @@
private void SendMail(string email)
{
var sendResult = UserDataService.SendForgottenPasswordMail(emailAddress).Forget;
msg = "We have sent you an email, with instructions on how to renew your password. ";
}
}

View File

@ -1,8 +1,10 @@
@page "/"
@using AyCode.Interfaces.StorageHandlers;
@using BlazorAnimation
@using TIAMSharedUI.Shared.Components
@using TIAMSharedUI.Shared.Components.BaseComponents
@using TIAMWebApp.Shared.Application.Interfaces
@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI
@using AyCode.Services.Loggers
@using TIAMSharedUI.Pages.Components;
@ -24,8 +26,8 @@
<AuthComponent />
<HeroSlider SliderItems="@sliders" PBottom="50px" Height="30vh"></HeroSlider>
@* <div class="container-fluid" style="position: relative; z-index: 2;">
<HeroSlider SliderItems="@sliders" PBottom="50px" Height="70vh"></HeroSlider>
@* <div class="container-fluid" style="position: relative; z-index: 2;">
<div class="row d-flex justify-content-center">
<div class="col-12 col-lg-6">
<div class="card bg-white p-3">
@ -42,9 +44,7 @@
</div> *@
<div class="container-fluid" style="align-content: center;">
@* <div class="container-fluid" style="align-content: center;">
<div class="text-center">
@ -52,49 +52,49 @@
<h2>@localizer.GetString("Index.Subtitle")</h2>
</div>
<div class="row">
</div> *@
<NavLink class="nav-link col-md-6 col-lg-4 col-12" href="transfer">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Fast" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card m-3 my-card text-white">
<img class="card-img" src="_content/TIAMSharedUI/images/m_transfer.jpg" alt="Card image">
<div class="card-img-overlay">
<h3 class="card-title">@localizer.GetString("Index.Transfer")</h3>
<p class="card-text">@localizer.GetString("Index.Transfer.Desc")</p>
</div>
</div>
</Animation>
</NavLink>
<NavLink class="nav-link col-md-6 col-lg-4 col-12" href="tours">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Fast" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card m-3 my-card text-white">
<img class="card-img" src="_content/TIAMSharedUI/images/m_tour.jpg" alt="Card image">
<div class="card-img-overlay">
<h3 class="card-title">@localizer.GetString("Index.Tours")</h3>
<p class="card-text">@localizer.GetString("Index.Tours.Desc")</p>
</div>
</div>
</Animation>
</NavLink>
<NavLink class="nav-link col-md-6 col-lg-4 col-12" href="clubcards">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Fast" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card m-3 my-card text-white">
<img class="card-img" src="_content/TIAMSharedUI/images/m_restaurant.jpg" alt="Card image">
<div class="card-img-overlay">
<h3 class="card-title">@localizer.GetString("Index.Clubcards")</h3>
<p class="card-text">@localizer.GetString("Index.Clubcards.Desc")</p>
</div>
</div>
</Animation>
</NavLink>
<section class="py-5 bg-light">
<div class="container">
<div class="row align-items-center">
<!-- Text Content -->
<div class="col-md-6">
<h2>@localizer.GetString("Index.WhoWeAre")</h2>
<p>Were not here to take over your trip. Were here to help shape it — with smooth rides, flexible options, and curated experiences you can actually enjoy.</p>
<p>Think of us as your private ride — whether youre heading to the airport, a spa town, a winery, or somewhere off the map.</p>
<p>You can follow one of our signature routes, or create your own. We adapt. You decide. We take care of the road.</p>
<p>Our role changes with every guest. Sometimes were your calm in the chaos. Sometimes were your quiet local expert. Sometimes were just there — when you need someone who knows the way.</p>
</div>
<!-- Image Placeholder -->
<div class="col-md-6 text-center">
<img src="https://images.unsplash.com/photo-1563461660947-507ef49e9c47?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Who we are" class="img-fluid rounded shadow">
</div>
</div>
</div>
</section>
</div>
<section class="py-5 bg-gradient">
<ToursComponent />
</section>
<section class="py-5">
<BlogComponent />
</section>
<CallToActionComponent></CallToActionComponent>
<script>
$(".custom-carousel").owlCarousel({
autoWidth: true,
loop: true
});
$(document).ready(function () {
$(".custom-carousel .item").click(function () {
$(".custom-carousel .item").not($(this)).removeClass("active");
$(this).toggleClass("active");
});
});
</script>
@code {
@ -102,18 +102,27 @@
{
new HeroSliderItem
{
Title = "Welcome to TIAM",
ImageUrl = "https://images.unsplash.com/photo-1551867633-194f125bddfa?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1551867633-194f125bddfa?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Explore Our Programs",
ButtonUrl= "/signature-ride-packages"
},
new HeroSliderItem
{
Title = "Welcome to TIAM",
ImageUrl = "https://images.unsplash.com/photo-1549877452-9c387954fbc2?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1549877452-9c387954fbc2?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Book now",
ButtonUrl= "/transfer"
},
new HeroSliderItem
{
Title = "Welcome to TIAM",
ImageUrl = "https://images.unsplash.com/photo-1507622560124-621e26755fb8?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
Title = "Experience Hungary on Your Terms",
Subtitle = "",
ImageUrl = "https://images.unsplash.com/photo-1507622560124-621e26755fb8?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "",
ButtonUrl= ""
}
};
@ -134,24 +143,37 @@
"Revenue"
};
/*protected override void OnAfterRender(bool isFirst)
{
message = " Target destination is " + slider.SliderElementId.ToString();
}*/
/*protected override void OnAfterRender(bool isFirst)
{
message = " Target destination is " + slider.SliderElementId.ToString();
}*/
public async Task SubmitForm(object Result)
{
TransferWizardModel transferWizardModel = Result as TransferWizardModel;
if(sessionService.IsAuthenticated)
{
transferWizardModel.UserId = sessionService.User.UserModelDto.Id;
transferWizardModel.ProductId = sessionService.User.UserModelDto.Products.FirstOrDefault().Id;
}
transferWizardModel.Price = null;
var transfer = await WizardProcessor.ProcessWizardAsync<TransferWizardModel>(transferWizardModel.GetType(), transferWizardModel);
BrowserConsoleLogWriter.Info($"Submitted nested form: {Result.GetType().FullName}");
navManager.NavigateTo("/transfer2/" + transfer.Id);
TransferWizardModel transferWizardModel = Result as TransferWizardModel;
if (sessionService.IsAuthenticated)
{
transferWizardModel.UserId = sessionService.User.UserModelDto.Id;
transferWizardModel.ProductId = sessionService.User.UserModelDto.Products.FirstOrDefault().Id;
}
transferWizardModel.Price = null;
var transfer = await WizardProcessor.ProcessWizardAsync<TransferWizardModel>(transferWizardModel.GetType(), transferWizardModel);
BrowserConsoleLogWriter.Info($"Submitted nested form: {Result.GetType().FullName}");
navManager.NavigateTo("/transfer2/" + transfer.Id);
}
public List<Event> MockEvents = new List<Event>
{
new Event("HONEYBEAST", "A Honeybeast egyedisége abban rejlik, hogy a popzenét rengeteg különféle irányból közelítik meg - hol vidám, hol szomorú, hol pörgős, hogy lassú, koncertjükön az érzelmek széles skáláját élhetjük át együtt.", "2024.05.03", "Budapest Park", "https://tixa.hu/kepek/0027/320/27870-1_20231214141702.jpg"),
new Event("VAD FRUTTIK", "A kék a tenger és az ég színe, a nyílt terekkel, valamint a képzelettel és tágassággal társul - végtelen kékség május 3-án a Budapest Parkban!", "2024.04.26", "Budapest Park", "https://tixa.hu/kepek/0027/768/27692-1_20231129185842.jpg"),
new Event("DEBORAH DE LUCA", "DEBORAH DE LUCA 2024-ben Magyarországon csak a Budapest Park színpadán", "2024.08.19", "Budapest Park", "https://tixa.hu/kepek/0028/768/28535-1_20240118172423.jpg"),
new Event("TOTAL DANCE CABRIO", "Ha nyár, akkor Total Dance Cabrio! Ülj be mellénk a cabrioba, és hagyd, hogy visszarepítsünk a 90-es és 2000-es évekbe! ", "2024.04.26", "Budapest Park", "https://tixa.hu/kepek/0027/768/27829-1_20231206193253.jpg"),
new Event("HONEYBEAST", "A Honeybeast egyedisége abban rejlik, hogy a popzenét rengeteg különféle irányból közelítik meg - hol vidám, hol szomorú, hol pörgős, hogy lassú, koncertjükön az érzelmek széles skáláját élhetjük át együtt.", "2024.05.03", "Budapest Park", "https://tixa.hu/kepek/0027/320/27870-1_20231214141702.jpg"),
new Event("VAD FRUTTIK", "A kék a tenger és az ég színe, a nyílt terekkel, valamint a képzelettel és tágassággal társul - végtelen kékség május 3-án a Budapest Parkban!", "2024.04.26", "Budapest Park", "https://tixa.hu/kepek/0027/768/27692-1_20231129185842.jpg"),
new Event("DEBORAH DE LUCA", "DEBORAH DE LUCA 2024-ben Magyarországon csak a Budapest Park színpadán", "2024.08.19", "Budapest Park", "https://tixa.hu/kepek/0028/768/28535-1_20240118172423.jpg"),
new Event("TOTAL DANCE CABRIO", "Ha nyár, akkor Total Dance Cabrio! Ülj be mellénk a cabrioba, és hagyd, hogy visszarepítsünk a 90-es és 2000-es évekbe! ", "2024.04.26", "Budapest Park", "https://tixa.hu/kepek/0027/768/27829-1_20231206193253.jpg"),
};
}

View File

@ -91,9 +91,10 @@
protected override async Task OnParametersSetAsync()
{
if(productId.IsNullOrEmpty())
if(!productId.IsNullOrEmpty())
{
var result = await _adminSignalRClient.GetByIdAsync<Product>(SignalRTags.GetCompaniesById, productId);
var result = await _adminSignalRClient.GetByIdAsync<Product>(SignalRTags.GetProductById, productId);
_logger.Debug($"Current product: {result.Name}");
if (result != null)
{
SelectedHotel = result;
@ -103,7 +104,7 @@
SelectedHotel = null;
}
}
_logger.Debug($"OnParameterSet, going forward");
if (!referralId.IsNullOrEmpty())
{
//check if storage has some other referralId already TODO

View File

@ -0,0 +1,71 @@
@page "/backgroundtest"
@inject IStringLocalizer<TIAMResources> localizer;
@using TIAM.Resources
@using TIAMSharedUI.Shared
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI
<div class="hero">
<div class="parallax-layer layer-6"></div>
<div class="parallax-layer layer-5"></div>
<div class="parallax-layer layer-4"></div>
<div class="parallax-layer bike-1"></div>
<div class="parallax-layer bike-2"></div>
<div class="parallax-layer layer-3"></div>
<div class="parallax-layer layer-2"></div>
<div class="parallax-layer layer-1"></div>
<div class="logo">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/logo.svg" alt="" />
</div>
</div>
<HeroSlider SliderItems="@sliders" PBottom="50px" Height="70vh"></HeroSlider>
<section class="py-5 bg-light">
<div class="container">
<div class="row align-items-center">
<!-- Text Content -->
<div class="col-md-6">
<h2>@localizer.GetString("Index.WhoWeAre")</h2>
<p>Were not here to take over your trip. Were here to help shape it — with smooth rides, flexible options, and curated experiences you can actually enjoy.</p>
<p>Think of us as your private ride — whether youre heading to the airport, a spa town, a winery, or somewhere off the map.</p>
<p>You can follow one of our signature routes, or create your own. We adapt. You decide. We take care of the road.</p>
<p>Our role changes with every guest. Sometimes were your calm in the chaos. Sometimes were your quiet local expert. Sometimes were just there — when you need someone who knows the way.</p>
</div>
<!-- Image Placeholder -->
<div class="col-md-6 text-center">
<img src="https://via.placeholder.com/500x350" alt="Who we are" class="img-fluid rounded shadow">
</div>
</div>
</div>
</section>
@code {
public List<HeroSliderItem> sliders = new List<HeroSliderItem>
{
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1551867633-194f125bddfa?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Explore Our Programs",
ButtonUrl= "/signature-ride-packages"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1549877452-9c387954fbc2?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Book now",
ButtonUrl= "/transfer"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "",
ImageUrl = "https://images.unsplash.com/photo-1507622560124-621e26755fb8?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "",
ButtonUrl= ""
}
};
}

View File

@ -0,0 +1,179 @@
* {
box-sizing: border-box;
}
body {
font-family: "Lato", sans-serif;
}
.hero {
width: 100%;
min-height: 450px;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #d9edfd;
z-index: -1;
}
.layer-1 {
-webkit-animation: parallax_fg linear 20s infinite both;
animation: parallax_fg linear 20s infinite both;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/1.png) 0 100% repeat-x;
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-size: auto 136px;
}
.layer-2 {
-webkit-animation: parallax_fg linear 30s infinite both;
animation: parallax_fg linear 30s infinite both;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/2.png) 0 100% repeat-x;
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-size: auto 145px;
}
.layer-3 {
-webkit-animation: parallax_fg linear 55s infinite both;
animation: parallax_fg linear 55s infinite both;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/3.png) 0 100% repeat-x;
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-size: auto 158px;
}
.layer-4 {
-webkit-animation: parallax_fg linear 75s infinite both;
animation: parallax_fg linear 75s infinite both;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/4.png) 0 100% repeat-x;
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-size: auto 468px;
}
.layer-5 {
-webkit-animation: parallax_fg linear 95s infinite both;
animation: parallax_fg linear 95s infinite both;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/5.png) 0 100% repeat-x;
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-size: auto 311px;
}
.layer-6 {
-webkit-animation: parallax_fg linear 120s infinite both;
animation: parallax_fg linear 120s infinite both;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/24650/6.png) 0 100% repeat-x;
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-size: auto 222px;
}
.bike-1,
.bike-2 {
background: url(images/car.png) 0 100% no-repeat;
z-index: 1;
position: fixed;
bottom: 100px;
left: 0;
width: 100%;
height: 100%;
background-size: auto 75px;
}
.bike-1 {
-webkit-animation: parallax_bike linear 10s infinite both;
animation: parallax_bike linear 10s infinite both;
}
.bike-2 {
-webkit-animation: parallax_bike linear 15s infinite both;
animation: parallax_bike linear 15s infinite both;
}
@-webkit-keyframes parallax_fg {
0% {
background-position: 2765px 100%;
}
100% {
background-position: 550px 100%;
}
}
@keyframes parallax_fg {
0% {
background-position: 2765px 100%;
}
100% {
background-position: 550px 100%;
}
}
@-webkit-keyframes parallax_bike {
0% {
background-position: -300px 100%;
}
100% {
background-position: 2000px 100%;
}
}
@keyframes parallax_bike {
0% {
background-position: -300px 100%;
}
100% {
background-position: 2000px 100%;
}
}
.logo {
margin: 70px auto;
position: absolute;
z-index: 2;
width: 100%;
}
.logo img {
display: block;
margin: 0 auto;
max-width: 100%;
}
@media (max-width: 700px) {
.logo img {
max-width: 90%;
}
}

View File

@ -1,72 +0,0 @@
@page "/tours"
@using TIAMSharedUI.Shared
<HeroSlider></HeroSlider>
<div class="container">
<section class="game-section" style="max-width: 100%; overflow-x:hidden">
<div class="text-center">
<h1>Tours</h1>
<h2>Please select!</h2>
</div>
<div class="owl-carousel custom-carousel owl-theme">
<a href="login">
<div class="item active" style="background-image: url(_content/TIAMSharedUI/images/slider1.jpg);">
<div class="item-desc">
<h3>Parliament of Hungary</h3>
<p>The Parliament of Hungary, located in Budapest, is a magnificent neo-Gothic building along the Danube River, housing the country's legislature and representing a symbol of Hungary's political and historical significance.</p>
</div>
</div>
</a>
<div class="item" style="background-image: url(_content/TIAMSharedUI/images/slider2.jpg);">
<div class="item-desc">
<h3>Buda Castle</h3>
<p>Buda Castle, located in Budapest, Hungary, is a historic palace complex that has served as the royal residence and administrative center for Hungarian kings throughout history. </p>
</div>
</div>
<div class="item" style="background-image: url(_content/TIAMSharedUI/images/slider3.jpg);">
<div class="item-desc">
<h3>Aggtelek National Park</h3>
<p>Aggtelek Cave, in northeastern Hungary, is a UNESCO World Heritage site renowned for its intricate karst formations, underground river, and breathtaking natural beauty, making it a must-visit destination for cave enthusiasts and nature lovers.</p>
</div>
</div>
<div class="item" style="background-image: url(_content/TIAMSharedUI/images/slider4.jpg);">
<div class="item-desc">
<h3>Margaret Island</h3>
<p>Margaret Island, also in Budapest, is a serene green oasis situated in the middle of the Danube River, offering recreational opportunities, gardens, and a relaxing escape from the city.</p>
</div>
</div>
<div class="item" style="background-image: url(_content/TIAMSharedUI/images/slider5.jpg);">
<div class="item-desc">
<h3>Heroes square</h3>
<p>Heroes' Square in Budapest, Hungary, is a grand public square featuring iconic statues and monuments honoring the nation's historic leaders and heroes.</p>
</div>
</div>
<div class="item" style="background-image: url(_content/TIAMSharedUI/images/slider6.jpg);">
<div class="item-desc">
<h3>Vajdahunyad Castle</h3>
<p>Vajdahunyad Castle, also in Budapest, is a fairytale-like complex showcasing architectural styles from various historical periods, making it a unique and picturesque cultural destination.</p>
</div>
</div>
</div>
</section>
<EventsComponent ItemType="0"></EventsComponent>
<FeaturedItems ItemType="0"></FeaturedItems>
</div>
<script>
$(".custom-carousel").owlCarousel({
autoWidth: true,
loop: true
});
$(document).ready(function () {
$(".custom-carousel .item").click(function () {
$(".custom-carousel .item").not($(this)).removeClass("active");
$(this).toggleClass("active");
});
});
</script>

View File

@ -0,0 +1,39 @@
@using TIAM.Entities.Transfers
@using TIAMWebApp.Shared.Application.Models
<EditForm Model="@Tour" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-3">
<label class="form-label">Title</label>
<InputText class="form-control" @bind-Value="Tour.Title" />
</div>
<div class="mb-3">
<label class="form-label">Fancy Description</label>
<InputTextArea class="form-control" @bind-Value="Tour.FancyDescription" rows="4" />
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-success">Save</button>
<button type="button" class="btn btn-secondary" @onclick="HandleCancel">Cancel</button>
</div>
</EditForm>
@code {
[Parameter] public TourInfo Tour { get; set; } = new();
[Parameter] public EventCallback<TourInfo> OnSave { get; set; }
[Parameter] public EventCallback OnCancel { get; set; }
private async Task HandleValidSubmit()
{
await OnSave.InvokeAsync(Tour);
}
private async Task HandleCancel()
{
await OnCancel.InvokeAsync(Tour);
}
}

View File

@ -0,0 +1,49 @@
@page "/signature-ride-packages"
@inject TourService TourService
@using TIAMSharedUI.Shared
@using TIAMSharedUI.Shared.Components
@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI
@using TIAMWebApp.Shared.Application.Services
@using Microsoft.AspNetCore.Components.Web
<HeroSlider SliderItems="@sliders" PBottom="50px" Height="30vh"></HeroSlider>
<ToursComponent />
@* <FeaturedItems ItemType="0" /> *@
@code {
public List<HeroSliderItem> sliders = new()
{
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1551867633-194f125bddfa?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Explore Our Programs",
ButtonUrl= "/signature-ride-packages"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1549877452-9c387954fbc2?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Book now",
ButtonUrl= "/transfer"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "",
ImageUrl = "https://images.unsplash.com/photo-1507622560124-621e26755fb8?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "",
ButtonUrl= ""
}
};
}

View File

@ -0,0 +1,419 @@
@page "/book-a-tour/{TransferDestinationId}/{PriceCategory:int}"
@using AyCode.Core.Consts
@using AyCode.Core.Helpers
@using TIAM.Models.Dtos.Users
@using TIAM.Services
@using TIAMSharedUI.Pages.Components
@using TIAMSharedUI.Pages.Components.EditComponents
@using TIAMSharedUI.Shared
@using TIAMSharedUI.Shared.Components.BaseComponents
@using TIAMWebApp.Shared.Application.Interfaces
@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels
@using AyCode.Services.Loggers
@using TIAMSharedUI.Pages.User.Hotels
@using TIAMWebApp.Shared.Application.Models.PageModels
@using TIAMWebApp.Shared.Application.Services
@using TIAMWebApp.Shared.Application.Utility
@inherits BasePageComponent
@inject NavigationManager navManager
@inject IEnumerable<IAcLogWriterClientBase> LogWriters
@inject IWizardProcessor WizardProcessor
@inject IUserDataService UserDataService
@inject AdminSignalRClient _adminSignalRClient
@inject ITransferDataService TransferDataService
@inject TourService TourService
<PageTitle>Transfer</PageTitle>
<HeroSlider SliderItems="sliders" Height="30vh"></HeroSlider>
<div class="container-fluid" style="position: relative; z-index: 2;">
<div class="row d-flex justify-content-center">
@{
if (_displayHelp)
{
<div class="col-md-6 col-12 px-5">
<!-- Step 1 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 1: Choose Your Transfer Direction
</p>
<p class="text-muted">At the top of the form, select whether you need a transfer <strong>"To the Airport"</strong> or <strong>"From the Airport"</strong> by clicking on the corresponding tab.</p>
</div>
</div>
<!-- Step 2 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 2: Enter the Destination (or Pickup) Address
</p>
<p class="text-muted">In the <strong>PickupAddress</strong> section, select your address:</p>
<ul>
<li><strong>Preset addresses:</strong> Click on the dropdown menu under “Preset addresses” and choose an address from the list. For example, you may see options like "Széchenyi fürdő."</li>
<li><strong>Custom address:</strong> If your address is not listed, click on the "Custom address" tab to manually enter your address.</li>
</ul>
</div>
</div>
<!-- Step 3 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 3: Confirm the Destination
</p>
<p class="text-muted">Once you select or enter the address, the form will display it as the "Selected address." Make sure this is correct before proceeding.</p>
</div>
</div>
<!-- Step 4 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 4: Enter Flight Information (Optional)
</p>
<p class="text-muted">If applicable, fill in your <strong>FlightNumber</strong>. This is optional, so you can leave it blank if you don't have or dont want to provide it.</p>
</div>
</div>
<!-- Step 5 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 5: Specify the Number of Passengers
</p>
<p>In the <strong>NumberOfPassengers</strong> field, enter the number of people who will be traveling. The default is set to 1, but you can change it as needed.</p>
</div>
</div>
<!-- Step 6 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 6: Indicate the Amount of Luggage
</p>
<p class="text-muted">In the <strong>NumberOfLuggage</strong> field, enter the total number of luggage items you will be bringing.</p>
</div>
</div>
<!-- Step 7 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 7: Fill in Your Personal Information
</p>
<p class="text-muted">Under <strong>FullName</strong>, enter your first and last name in the respective fields. Provide your <strong>PhoneNumber</strong> in the designated field. The phone number appears to be pre-filled with a sample number ("+11234567890"), so be sure to update it with your actual contact number. Enter your <strong>EmailAddress</strong> to receive confirmation and any further communication regarding your transfer.</p>
</div>
</div>
<!-- Step 8 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 8: Add Additional Comments (Optional)
</p>
<p class="text-muted">If you have any special requests or additional information youd like to provide, use the <strong>Comment</strong> section to do so.</p>
</div>
</div>
<!-- Step 9 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 9: Submit Your Request
</p>
<p>Once all fields are filled in correctly, click the <strong>Submit</strong> button at the bottom of the form to place your transfer order.</p>
</div>
</div>
<!-- Step 10 -->
<div class="card mb-3 shadow-sm">
<div class="card-body">
<p>
Step 10: Confirmation
</p>
<p>After submitting, you should receive a confirmation email or message. Ensure all the details are correct, and youre all set!</p>
</div>
</div>
</div>
}
}
<div class="col-12 col-md-6">
<DxToolbar ItemRenderStyleMode="ToolbarRenderStyleMode.Contained">
<Items>
<DxToolbarItem Alignment="ToolbarItemAlignment.Right" Text="Help" RenderStyle="ButtonRenderStyle.Secondary" IconCssClass="grid-icon-column-chooser" Click="ShowHelp_Click" />
</Items>
</DxToolbar>
<div style="max-height: 300px; overflow-y: hidden">
<img class="img-fluid" src="@tourInfo.CoverImageUrl" alt="@tourInfo.Title"/>
</div>
<DynamicEditForm Data="_myModel" TitleString="@($"To: {tourInfo.Title}, Price: {_myModel.Price} EUR")" isEditing="true" IgnoreReflection="_transferIgnorList1" OnSubmit="SubmitForm"></DynamicEditForm>
<InputWizard Data=@_myModel
OnSubmit="SubmitForm"
IgnoreReflection="@_transferIgnorList1"
SubmitButtonText="ButtonSend"
TitleResourceString="TransferTitle"
SubtitleResourceString="TransferSubtitle"></InputWizard>
</div>
</div>
</div>
<div class="container mt-5">
<div class="row align-items-center">
<div class="col-12 col-sm-6 p-5">
<h1>Book an Airport Transfer</h1>
<p>Welcome to Tour I Am! Book your airport transfer with us for a smooth and stress-free experience. Our professional drivers are ready to take you to and from the airport in comfort and style. We offer competitive rates and reliable service, ensuring you get to your destination on time.</p>
<h2>Why Choose Tour I Am?</h2>
<ul class="list-unstyled">
<li><strong>Reliable Service:</strong> Punctual pickups and drop-offs.</li>
<li><strong>Professional Drivers:</strong> Experienced and courteous drivers.</li>
<li><strong>Affordable Rates:</strong> Competitive pricing with no hidden fees.</li>
<li><strong>Comfortable Vehicles:</strong> Clean, modern, and well-maintained cars.</li>
</ul>
</div>
<div class="col-12 col-sm-6 p-5">
<img class="img-fluid" src="_content/TIAMSharedUI/images/about1.jpg" />
</div>
<div class="col-12 col-sm-6 p-5">
<img class="img-fluid" src="_content/TIAMSharedUI/images/about2.jpg" />
</div>
<div class="col-12 col-sm-6 p-5">
<h2>How to Book</h2>
<p>Booking your airport transfer is easy! Simply visit our <a href="/transfer">booking page</a>, enter your details, and confirm your reservation. You can also contact us at <a href="mailto:info@touriam.com">info@touriam.com</a> or call us at (123) 456-7890 for assistance.</p>
<p>Experience the convenience and reliability of Tour I Am. Book your airport transfer today and travel with peace of mind!</p>
</div>
</div>
</div>
@code {
[Parameter] public string TransferDestinationId { get; set; }
[Parameter] public int PriceCategory { get; set; } = 1;
private LoggerClient<TransferPage> _logger;
private readonly TransferWizardModel _myModel = new TransferWizardModel();
private TourInfo? tourInfo = new();
private bool _displayHelp = false;
public List<HeroSliderItem> sliders = new List<HeroSliderItem>
{
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1551867633-194f125bddfa?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Explore Our Programs",
ButtonUrl= "/signature-ride-packages"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "Discover the freedom of personalized travel with expert private transfers and curated inspiration.",
ImageUrl = "https://images.unsplash.com/photo-1549877452-9c387954fbc2?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "Book now",
ButtonUrl= "/transfer"
},
new HeroSliderItem
{
Title = "Experience Hungary on Your Terms",
Subtitle = "",
ImageUrl = "https://images.unsplash.com/photo-1507622560124-621e26755fb8?auto=format&fit=crop&q=80&w=2070&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
ButtonText = "",
ButtonUrl= ""
}
};
private readonly List<string> _transferIgnorList1 =
[
"Id",
"Destination",
"UserId",
"ProductId",
"PaymentId",
"FirstName",
"LastName",
"UserProductMappingId",
"UserProductToCarId",
"ReferralId",
"Price"
];
public async Task SubmitForm(object result)
{
var resModel = (TransferWizardModel)result;
//let's check if user exists with this email
var user = await UserDataService.GetUserByEmailAsync(resModel.EmailAddress!);
if (user != null && user.Id != Guid.Empty)
{
resModel.UserId = user.Id;
//user exists already
if (_sessionService.User != null)
{
if (_sessionService.User.UserId == user.Id)
{
//I have ordered for myself
resModel.ReferralId = null;
}
else
{
//if I am logged in and different user I become referrer (if no referrer already)
var transferUserDetail = await UserDataService.GetUserDetailByIdAsync(user.Id);
var userDetail = await UserDataService.GetUserDetailByIdAsync(_sessionService.User.UserId);
if (transferUserDetail.UserDto.RefferalId != null)
{
//user has aready a referrer so we use that
resModel.ReferralId = transferUserDetail.UserDto.RefferalId;
}
else
{
//user has no referrer so I am the referrer
resModel.ReferralId = userDetail.UserDto.RefferalId;
}
}
}
}
else
{
//create a guest user and set referralId
var registration = new RegistrationModel();
var password = AcCharsGenerator.NewPassword(AcConst.MinPasswordLength, 16);
registration.Email = resModel.EmailAddress;
registration.PhoneNumber = resModel.PhoneNumber;
registration.Password = password;
//get list with one member!
var createResult = await UserDataService.CreateGuestUser(registration);
if (createResult.isSuccess)
{
if (createResult.user != null)
{
if (_sessionService.User != null)
{
//if I am logged in user I become referrer
var userDetail = await UserDataService.GetUserDetailByIdAsync(_sessionService.User.UserId);
var createdUserDetail = await UserDataService.GetUserDetailByIdAsync(createResult.user.Id);
if (createdUserDetail != null)
{
createdUserDetail.UserDto.RefferalId = userDetail.UserDto.RefferalId;
var updatedNewUser = await _adminSignalRClient.UpdateUserModelDtoDetail(userDetail);
if (updatedNewUser != null)
{
//referral set
}
else
{
//something wrong
}
}
resModel.ReferralId = userDetail.UserDto.RefferalId;
}
resModel.UserId = createResult.user.Id;
}
else
{
//some error handling
}
}
}
var transfer = await WizardProcessor.ProcessWizardAsync<TransferWizardModel>(result.GetType(), result);
_logger.Info($"Submitted nested form: {result.GetType().FullName}");
navManager.NavigateTo($"/mytransfers/{resModel.Id}");
}
protected override Task OnInitializedAsync()
{
_logger = new LoggerClient<TransferPage>(LogWriters.ToArray());
return base.OnInitializedAsync();
}
protected override async Task OnParametersSetAsync()
{
//get transferDestination
var destination = await TransferDataService.GetTransferDestinationbyIdAsync(Guid.Parse(TransferDestinationId));
_myModel.Destination = destination.AddressString;
switch (PriceCategory)
{
case 1:
_myModel.Price = destination.Price;
break;
case 2:
_myModel.Price = destination.Price2;
break;
case 3:
_myModel.Price = destination.Price3;
break;
}
tourInfo = await TourService.GetAsync(destination.Id);
await base.OnParametersSetAsync();
}
private void ShowHelp_Click()
{
_displayHelp = !_displayHelp;
}
}

View File

@ -0,0 +1,202 @@
.container {
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
@media (min-width: 768px) {
.container {
width: 750px;
}
}
@media (min-width: 992px) {
.container {
width: 970px;
}
}
@media (min-width: 1200px) {
.container {
width: 1170px;
}
}
@media (max-width: 767px) {
#featureContainer .carousel-inner .carousel-item > div {
display: none;
}
#featureContainer .carousel-inner .carousel-item > div:first-child {
display: block;
}
}
#featureContainer .carousel-inner .carousel-item.active,
#featureContainer .carousel-inner .carousel-item-next,
#featureContainer .carousel-inner .carousel-item-prev {
display: flex;
}
@media (min-width: 768px) {
#featureContainer .carousel-inner .carousel-item-end.active,
#featureContainer .carousel-inner .carousel-item-next {
transform: translateX(25%);
}
#featureContainer .carousel-inner .carousel-item-start.active,
#featureContainer .carousel-inner .carousel-item-prev {
transform: translateX(-25%);
}
#featureContainer .card img {
width: 90%;
height: 40vh;
}
#featureContainer .carousel-item {
justify-content: space-between;
}
}
@media (max-width: 767px) {
#featureContainer .card img {
width: 100%;
height: 75vh;
}
}
#featureContainer .carousel-inner .carousel-item-end,
#featureContainer .carousel-inner .carousel-item-start {
transform: translateX(0);
}
#featureContainer .card {
border: 0;
}
#featureContainer .card {
position: relative;
}
#featureContainer .card .card-img-overlays {
position: absolute;
bottom: 15%;
left: 10%;
}
#featureContainer a {
text-decoration: none;
}
#featureContainer .indicator {
border: 1px solid rgb(202, 202, 202);
padding: 3px 6px 3px 6px;
}
#featureContainer .indicator:hover {
background-color: blue;
border: 1px solid blue;
transition: 200ms;
}
#featureContainer .indicator:hover {
color: white;
transition: 200ms;
}
#featureContainer .indicator {
color: lightgray;
}
#featureContainer .float-end {
padding-top: 10px;
}
/* Reseting */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
.wrapper {
max-width: 800px;
min-height: 500px;
margin: 10px auto;
padding: 30px 30px 30px 30px;
/*background-color: #ecf0f3;*/
border-radius: 15px;
/*box-shadow: 13px 13px 20px #cbced1, -13px -13px 20px #fff;*/
}
.wrapper .name {
font-weight: 600;
font-size: 1.4rem;
letter-spacing: 1.3px;
padding-left: 10px;
/*color: #555*/;
}
.wrapper .form-field input {
width: 100%;
display: block;
border: none;
outline: none;
background: none;
font-size: 1.2rem;
color: #666;
padding: 10px 15px 10px 10px;
/* border: 1px solid red; */
}
.wrapper .form-field {
padding-left: 10px;
margin-bottom: 20px;
border-bottom: 1px solid;
/*border-radius: 20px;*/
//*ox-shadow: inset 3px 3px 3px #cbced1, inset -3px -3px 3px #fff;*/
}
.wrapper .form-field .fas {
color: #555;
}
.wrapper .btn {
box-shadow: none;
width: 100%;
height: 40px;
/*background-color: #03A9F4;*/
color: #fff;
border-radius: 15px;
/*box-shadow: 3px 3px 3px #b1b1b1, -3px -3px 3px #fff;*/
letter-spacing: 1.3px;
}
.wrapper .btn:hover {
background-color: #039BE5;
}
.wrapper a {
text-decoration: none;
font-size: 0.8rem;
color: #03A9F4;
}
.wrapper a:hover {
color: #039BE5;
}
@media(max-width: 380px) {
.wrapper {
margin: 30px 20px;
padding: 40px 15px 15px 15px;
}
}

View File

@ -268,7 +268,6 @@
"UserId",
"ProductId",
"PaymentId",
"TripDate",
"FirstName",
"LastName",
"UserProductMappingId",
@ -284,7 +283,6 @@
"UserId",
"ProductId",
"PaymentId",
"TripDate",
"FirstName",
"LastName",
"UserProductMappingId",
@ -405,7 +403,7 @@
var transfer = await WizardProcessor.ProcessWizardAsync<TransferWizardModel>(result.GetType(), result);
_logger.Info($"Submitted nested form: {result.GetType().FullName}");
navManager.NavigateTo($"/transfer2/{resModel.Id}");
navManager.NavigateTo($"/mytransfers/{resModel.Id}");
}
protected override Task OnInitializedAsync()

View File

@ -116,7 +116,7 @@
void OnPasswordSet(string password)
{
msg = $"Password to set: {NewPassword}";
msg = $"Please type in again";
PasswordNotSet = false;
StateHasChanged();

View File

@ -103,6 +103,7 @@
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="Appointment" SortOrder="GridColumnSortOrder.Descending" GroupIndex="0" GroupInterval="GridColumnGroupInterval.Custom" DisplayFormat="g" Width="125" />
<DxGridDataColumn FieldName="FullName" />
<DxGridDataColumn FieldName="ContactPhone" Width="120" />
<DxGridDataColumn FieldName="ContactEmail" Width="120" />

View File

@ -0,0 +1,183 @@
@page "/sysadmin/blogs"
@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Services
@using TIAMSharedUI.Shared
@layout AdminLayout
@inject BlogService BlogService
<div clss="container">
<h3 class="mb-4">Manage Blog Posts</h3>
<EditForm Model="@Post" OnValidSubmit="@SavePost">
<div class="mb-3">
<label class="form-label">Title</label>
<InputText class="form-control" @bind-Value="Post.Title" />
</div>
<div class="mb-3">
<label class="form-label">Lead</label>
<InputText class="form-control" @bind-Value="Post.Lead" />
</div>
<div class="mb-3">
<label class="form-label">Google Drive Link</label>
<InputText class="form-control" @bind-Value="Post.DriveLink" />
</div>
<div class="mb-3">
<label class="form-label">Tags (comma-separated)</label>
<InputText class="form-control" @bind-Value="TagsCsv" />
</div>
<div class="mb-3">
<label class="form-label">Cover Image (optional)</label>
<InputFile OnChange="@HandleFileSelected" />
</div>
<button class="btn btn-primary" type="submit" disabled="@IsSaving">
@if (IsSaving)
{
<span class="spinner-border spinner-border-sm"></span> @(IsEditMode ? "Updating..." : "Saving...")
}
else
{
<span>@(IsEditMode ? "Update Post" : "Save Post")</span>
}
</button>
@if (IsEditMode)
{
<button type="button" class="btn btn-secondary ms-2" @onclick="CancelEdit">Cancel</button>
}
</EditForm>
@if (SaveSuccess)
{
<div class="alert alert-success mt-3">Post saved successfully!</div>
}
<h4 class="mt-5">Existing Posts</h4>
@if (Posts.Count == 0)
{
<p>No blog posts found.</p>
}
else
{
<table class="table table-bordered mt-3">
<thead>
<tr>
<th>Title</th>
<th>Tags</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Posts)
{
<tr>
<td><img src="@item.CoverImage" style="max-height:150px" /></td>
<td>@item.Title</td>
<td>@string.Join(", ", item.Tags)</td>
<td>
<button class="btn btn-sm btn-primary me-2" @onclick="() => EditPost(item)">Edit</button>
<button class="btn btn-sm btn-danger" @onclick="() => DeletePost(item.Id)">Delete</button>
</td>
</tr>
}
</tbody>
</table>
}
</div>
@code {
private BlogPostMetadata Post = new();
private List<BlogPostMetadata> Posts = new();
private IBrowserFile? CoverImage;
private string TagsCsv = "";
private bool IsSaving = false;
private bool SaveSuccess = false;
private bool IsEditMode = false;
protected override async Task OnInitializedAsync()
{
await LoadPosts();
}
private async Task LoadPosts()
{
Posts = await BlogService.GetAllPostsAsync();
}
private async Task HandleFileSelected(InputFileChangeEventArgs e)
{
CoverImage = e.File;
}
private async Task SavePost()
{
IsSaving = true;
SaveSuccess = false;
Post.Tags = TagsCsv.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
if (IsEditMode)
{
await BlogService.UpdatePostAsync(Post, CoverImage);
}
else
{
await BlogService.CreatePostAsync(Post, CoverImage);
}
IsSaving = false;
SaveSuccess = true;
await LoadPosts();
ResetForm();
}
private void EditPost(BlogPostMetadata post)
{
Post = new BlogPostMetadata
{
Id = post.Id,
Title = post.Title,
Lead = post.Lead,
DriveLink = post.DriveLink,
Tags = new List<string>(post.Tags),
CoverImage = post.CoverImage
};
TagsCsv = string.Join(", ", post.Tags);
IsEditMode = true;
SaveSuccess = false;
}
private async Task DeletePost(string id)
{
if (await ConfirmDeleteAsync())
{
await BlogService.DeletePostAsync(id);
await LoadPosts();
}
}
private async Task<bool> ConfirmDeleteAsync()
{
return await Task.FromResult(true); // Replace with real confirmation popup later
}
private void CancelEdit()
{
ResetForm();
}
private void ResetForm()
{
Post = new BlogPostMetadata();
TagsCsv = "";
CoverImage = null;
IsEditMode = false;
}
}

View File

@ -129,7 +129,7 @@
private static DateTime _toDate = DateTime.Today;
private static int _takeCount = 250;
private object[] _contextParams = new object[3] { _takeCount, _fromDate, _toDate };
private object[] _contextParams = [_takeCount, _fromDate, _toDate];
private LoggerClient<LogViewerGridComponent> _logger;
private static List<LogLevel> _selectedLogLevels = [LogLevel.Error, LogLevel.Warning, LogLevel.Suggest];
@ -154,12 +154,12 @@
if (_selectedLogLevels.Count > 0)
{
filterCriteria = new InOperator(nameof(LogLevel), _selectedLogLevels);
filterCriteria = new InOperator(nameof(LogItemViewerModel.LogLevel), _selectedLogLevels);
filterText = GetFilterText(_selectedLogLevels);
}
_filterText = filterText;
_logViewerGrid.SetFieldFilterCriteria(nameof(LogLevel), filterCriteria);
_logViewerGrid.SetFieldFilterCriteria(nameof(LogItemViewerModel.LogLevel), filterCriteria);
}
private async Task OnValueChangedTakeCount(int value)
@ -199,7 +199,7 @@
{
if (e.ElementType != GridElementType.DataRow) return;
var logLevelObject = e.Grid?.GetRowValue(e.VisibleIndex, nameof(LogLevel));
var logLevelObject = e.Grid?.GetRowValue(e.VisibleIndex, nameof(LogItemViewerModel.LogLevel));
if (logLevelObject == null) return;
var levelObject = (LogLevel)logLevelObject;

View File

@ -4,6 +4,7 @@
@using TIAM.Core.Enums
@using TIAM.Entities.Emails
@using TIAM.Entities.Transfers
@using TIAM.Entities.Users
@using TIAM.Resources
@using TIAMSharedUI.Pages.Components
@using TIAMSharedUI.Shared
@ -20,8 +21,10 @@
@using AyCode.Core
@using AyCode.Core.Helpers
@using DevExpress.Data.Filtering
@using TIAM.Entities.Drivers
@using TIAM.Entities.Emails
@using TIAMSharedUI.Shared.Components.BaseComponents
@using TIAM.Services
@inherits UserBasePageComponent
@layout AdminLayout
@inject IWizardProcessor wizardProcessor
@ -30,465 +33,543 @@
<PageTitle>Transfers</PageTitle>
<div class="text-center m-5">
<h1>Transfer management</h1>
<h2 style="font-size:small">Manage transfers here!</h2>
<h1>Transfer management</h1>
<h2 style="font-size:small">Manage transfers here!</h2>
</div>
<DxPopup CssClass="popup-demo-events"
@bind-Visible="@_popupVisible"
ShowFooter="true"
CloseOnEscape="true"
CloseOnOutsideClick="false"
ShowCloseButton="false"
HeaderText="MessageBox"
Closing="EulaPopupClosing"
Closed="EulaPopupClosed">
<BodyContentTemplate>
<InputWizard Data=@_messageWizardModel
OnSubmit="SubmitForm"
IgnoreReflection=@IgnoreList
TitleResourceString="NewMessage"
SubtitleResourceString="NewMessageSubtitle"
SubmitButtonText="@_localizer.GetString("ButtonSend")"></InputWizard>
</BodyContentTemplate>
<FooterContentTemplate Context="Context">
<div class="popup-demo-events-footer">
<!--DxCheckBox CssClass="popup-demo-events-checkbox" @bind-Checked="@EulaAccepted">I accept the terms of the EULA</!--DxCheckBox-->
<!--DxButton CssClass="popup-demo-events-button ms-2" RenderStyle="ButtonRenderStyle.Primary" Text="OK" Click="Context.CloseCallback" /-->
<DxButton CssClass="popup-demo-events-button ms-2" RenderStyle="ButtonRenderStyle.Secondary" Text="Cancel" Click="CancelCreateClick" />
</div>
</FooterContentTemplate>
@bind-Visible="@_popupVisible"
ShowFooter="true"
CloseOnEscape="true"
CloseOnOutsideClick="false"
ShowCloseButton="false"
HeaderText="MessageBox"
Closing="EulaPopupClosing"
Closed="EulaPopupClosed">
<BodyContentTemplate>
<InputWizard Data=@_messageWizardModel
OnSubmit="SubmitForm"
IgnoreReflection=@IgnoreList
TitleResourceString="NewMessage"
SubtitleResourceString="NewMessageSubtitle"
SubmitButtonText="@_localizer.GetString("ButtonSend")"></InputWizard>
</BodyContentTemplate>
<FooterContentTemplate Context="Context">
<div class="popup-demo-events-footer">
<!--DxCheckBox CssClass="popup-demo-events-checkbox" @bind-Checked="@EulaAccepted">I accept the terms of the EULA</!--DxCheckBox-->
<!--DxButton CssClass="popup-demo-events-button ms-2" RenderStyle="ButtonRenderStyle.Primary" Text="OK" Click="Context.CloseCallback" /-->
<DxButton CssClass="popup-demo-events-button ms-2" RenderStyle="ButtonRenderStyle.Secondary" Text="Cancel" Click="CancelCreateClick" />
</div>
</FooterContentTemplate>
</DxPopup>
<div class="container-fluid">
<div class="row">
<div class=" col-12">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Fast" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card">
<div class="row">
<div class=" col-12">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Fast" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card">
<DxTabs>
<DxTabs>
<DxTabPage Text="DataGrid">
<div class="d-flex flex-column mb-4 pb-2">
<div class="align-self-end pl-2 pb-2">
<DxButton Text="Column Chooser"
RenderStyle="ButtonRenderStyle.Secondary"
IconCssClass="btn-column-chooser"
Click="ColumnChooserButton_Click" />
</div>
<DxTabPage Text="DataGrid">
<div class="d-flex flex-column mb-4 pb-2">
<div class="align-self-end pl-2 pb-2">
<DxButton Text="Column Chooser"
RenderStyle="ButtonRenderStyle.Secondary"
IconCssClass="btn-column-chooser"
Click="ColumnChooserButton_Click" />
</div>
<TransferGrid @ref="_gridTransfer"
Logger="_logger"
SignalRClient="AdminSignalRClient"
FilterText="@_filterText"
OnDataSourceChanged="DataSourceChanged"
OnGridItemChanging="DataSourceItemChanging"
OnGridItemChanged="DataSourceItemChanged"
OnGridItemDeleting="DataItemDeleting"
OnGridEditModelSaving="DataItemSaving"
CustomizeElement="Grid_CustomizeElement"
CustomizeEditModel="Grid_CustomizeEditModel"
EditMode="GridEditMode.EditForm"
ColumnResizeMode="GridColumnResizeMode.NextColumn"
PageSize="13"
ShowFilterRow="true">
<TransferGrid @ref="_gridTransfer"
Logger="_logger"
SignalRClient="AdminSignalRClient"
FilterText="@_filterText"
OnDataSourceChanged="DataSourceChanged"
OnGridItemChanging="DataSourceItemChanging"
OnGridItemChanged="DataSourceItemChanged"
OnGridItemDeleting="DataItemDeleting"
OnGridEditModelSaving="DataItemSaving"
SelectedDataItemChanged="OnSelectedDataItemChanged"
CustomizeElement="Grid_CustomizeElement"
CustomizeEditModel="Grid_CustomizeEditModel"
EditMode="GridEditMode.EditForm"
ColumnResizeMode="GridColumnResizeMode.NextColumn"
PageSize="13"
ShowFilterRow="true">
<Columns>
<DxGridCommandColumn NewButtonVisible="false" DeleteButtonVisible="AcDomain.IsDeveloperVersion" Width="80" MinWidth="80" FixedPosition="GridColumnFixedPosition.Left" />
<DxGridDataColumn FieldName="Id" ShowInColumnChooser="AcDomain.IsDeveloperVersion" Visible="AcDomain.IsDeveloperVersion" DisplayFormat="N" />
<DxGridDataColumn FieldName="OrderId" Caption="Order" SortIndex="1" SortOrder="GridColumnSortOrder.Descending" Width="70">
<CellDisplayTemplate>
@{
var idKeyField = ((Transfer)context.DataItem).Id.ToString("N");
var editUri = $"mytransfers/{idKeyField}";
<NavLink href="@editUri">
<text>@context.Value</text>
</NavLink>
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="FromAddress" />
<DxGridDataColumn FieldName="ToAddress" />
<DxGridDataColumn FieldName="Appointment" DisplayFormat="g" Width="125" />
<DxGridDataColumn FieldName="PassengerCount" Caption="Passengers" Width="90" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="LuggageCount" Caption="Luggages" Width="80" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="FlightNumber" Caption="FlightNum" Width="95" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="Price" Caption="Price" Width="70" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="Revenue" Caption="Revenue" Width="70" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="FullName" />
<DxGridDataColumn FieldName="ContactPhone" Width="120" />
<DxGridDataColumn FieldName="ContactEmail" Width="120">
<CellDisplayTemplate>
@{
var keyField = context.Value;
var keyItem = (Transfer)context.DataItem;
string buttonText = "Contact";
<DxButton Click="() => SendMail(keyItem)" Text="@buttonText" RenderStyle="ButtonRenderStyle.Primary" />
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="PaymentId" DisplayFormat="N" Visible="false" />
<DxGridDataColumn Caption="Paid" FieldName="Paid" Width="75" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="TransferStatusType" Caption="Status" SortIndex="0" Width="120" SortOrder="GridColumnSortOrder.Ascending" SortMode="GridColumnSortMode.Value">
<CellDisplayTemplate>
@{
<Columns>
<DxGridCommandColumn NewButtonVisible="false" DeleteButtonVisible="AcDomain.IsDeveloperVersion" Width="80" MinWidth="80" FixedPosition="GridColumnFixedPosition.Left" />
<DxGridDataColumn FieldName="Id" ShowInColumnChooser="AcDomain.IsDeveloperVersion" Visible="AcDomain.IsDeveloperVersion" DisplayFormat="N" />
<DxGridDataColumn FieldName="OrderId" Caption="Order" SortIndex="1" SortOrder="GridColumnSortOrder.Descending" Width="70">
<CellDisplayTemplate>
@{
var idKeyField = ((Transfer)context.DataItem).Id.ToString("N");
var editUri = $"mytransfers/{idKeyField}";
<NavLink href="@editUri">
<text>@context.Value</text>
</NavLink>
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="FromAddress" />
<DxGridDataColumn FieldName="ToAddress" />
<DxGridDataColumn FieldName="Appointment" DisplayFormat="g" Width="125" />
<DxGridDataColumn FieldName="PassengerCount" Caption="Passengers" Width="90" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="LuggageCount" Caption="Luggages" Width="80" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="FlightNumber" Caption="FlightNum" Width="95" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="Price" Caption="Price" Width="70" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="Revenue" Caption="Revenue" Width="70" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="FullName" />
<DxGridDataColumn Caption="Driver" Width="120">
<CellDisplayTemplate>
@{
var keyItem = (Transfer)context.DataItem;
<text>@(string.Join(", ", keyItem.TransferToDrivers.Select(x => x.UserProductMapping?.User?.Profile?.GetFullName())))</text>
}
</CellDisplayTemplate>
TransferStatusModel keyField = TransferStatusModel.GetStatusModel((TransferStatusType)context.Value);
string transferStatusText = keyField.StatusName;
<text>@transferStatusText</text>
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="ReferralId" DisplayFormat="N" Visible="false" />
<DxGridDataColumn FieldName="Comment" Caption="Comment" />
<DxGridDataColumn FieldName="Created" DisplayFormat="g" Width="125" Visible="false" CaptionAlignment="GridTextAlignment.Center" TextAlignment="GridTextAlignment.Center" />
</Columns>
<DetailRowTemplate>
<DxTabs>
<DxTabPage Text="Messages">
<MessageDetailGridComponent ContextId="((Transfer)context.DataItem).Id" />
</DxTabPage>
<DxTabPage Text="Driver">
<TransferToDriverGridComponent ContextId="((Transfer)context.DataItem).Id" ParentData="(Transfer)context.DataItem" />
</DxTabPage>
</DxTabs>
</DetailRowTemplate>
<EditFormTemplate Context="editFormContext">
@{
var transfer2 = (Transfer)editFormContext.EditModel;
}
<DxFormLayout CssClass="w-100">
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.FirstName) ColSpanMd="6">
@editFormContext.GetEditor("FirstName")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.LastName) ColSpanMd="6">
@editFormContext.GetEditor("LastName")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.DestinationAddress) ColSpanMd="6">
@editFormContext.GetEditor("ToAddress")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.PickupAddress) ColSpanMd="6">
@editFormContext.GetEditor("FromAddress")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Trip date:" ColSpanMd="3">
</DxGridDataColumn>
<DxGridDataColumn FieldName="ContactPhone" Width="120" />
<DxGridDataColumn FieldName="ContactEmail" Width="120" />
<DxDateEdit @bind-Date="@transfer2.Appointment"
TimeSectionVisible="true"
TimeSectionScrollPickerFormat="tt h m">
</DxDateEdit>
<DxGridDataColumn FieldName="ContactEmail" Width="120">
<CellDisplayTemplate>
@{
var keyItem = (Transfer)context.DataItem;
var buttonText = "Contact";
<DxButton Click="() => SendMail(keyItem)" Text="@buttonText" RenderStyle="ButtonRenderStyle.Primary" />
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="PaymentId" DisplayFormat="N" Visible="false" />
<DxGridDataColumn Caption="Paid" FieldName="Paid" Width="75" TextAlignment="GridTextAlignment.Center" CaptionAlignment="GridTextAlignment.Center" />
<DxGridDataColumn FieldName="TransferStatusType" Caption="Status" SortIndex="0" Width="120" SortOrder="GridColumnSortOrder.Ascending" SortMode="GridColumnSortMode.Value">
<CellDisplayTemplate>
@{
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Passengers:" ColSpanMd="3">
@editFormContext.GetEditor("PassengerCount")
</DxFormLayoutItem>
var keyField = TransferStatusModel.GetStatusModel((TransferStatusType)context.Value);
var transferStatusText = keyField.StatusName;
<text>@transferStatusText</text>
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="ReferralId" DisplayFormat="N" Visible="false" />
<DxGridDataColumn FieldName="Comment" Caption="Comment" />
<DxGridDataColumn FieldName="Created" DisplayFormat="g" Width="125" Visible="false" CaptionAlignment="GridTextAlignment.Center" TextAlignment="GridTextAlignment.Center" />
</Columns>
<DetailRowTemplate>
<DxTabs>
<DxTabPage Text="Messages">
<MessageDetailGridComponent ContextId="((Transfer)context.DataItem).Id" />
</DxTabPage>
<DxTabPage Text="Driver">
<TransferToDriverGridComponent ContextId="((Transfer)context.DataItem).Id" ParentData="(Transfer)context.DataItem" />
</DxTabPage>
</DxTabs>
</DetailRowTemplate>
<EditFormTemplate Context="editFormContext">
@{
var transfer2 = (Transfer)editFormContext.EditModel;
}
<DxFormLayout CssClass="w-100">
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.FirstName) ColSpanMd="6">
@editFormContext.GetEditor("FirstName")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.LastName) ColSpanMd="6">
@editFormContext.GetEditor("LastName")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.EmailAddress) ColSpanMd="6">
@editFormContext.GetEditor("ContactEmail")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.DestinationAddress) ColSpanMd="6">
@editFormContext.GetEditor("ToAddress")
</DxFormLayoutItem>
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.PickupAddress) ColSpanMd="6">
@editFormContext.GetEditor("FromAddress")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Trip date:" ColSpanMd="3">
<DxDateEdit @bind-Date="@transfer2.Appointment"
TimeSectionVisible="true"
TimeSectionScrollPickerFormat="tt h m">
</DxDateEdit>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Passengers:" ColSpanMd="3">
@editFormContext.GetEditor("PassengerCount")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Paid:" ColSpanMd="3">
@editFormContext.GetEditor("Payed")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Paid:" ColSpanMd="3">
@editFormContext.GetEditor("Payed")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Status:" ColSpanMd="3">
@editFormContext.GetEditor("TransferStatusType")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Price:" ColSpanMd="3">
@editFormContext.GetEditor("Price")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Status:" ColSpanMd="3">
@editFormContext.GetEditor("TransferStatusType")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Price:" ColSpanMd="3">
@editFormContext.GetEditor("Price")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Revenue:" ColSpanMd="3">
@editFormContext.GetEditor("Revenue")
</DxFormLayoutItem>
</DxFormLayout>
</EditFormTemplate>
</DxFormLayout>
</EditFormTemplate>
<ToolbarTemplate>
<div>
<DxTagBox Data="@TransferStatusModel.AllStatuses.Values" Values="@_selectedCategories" @ref="_filterTag"
ValuesChanged="(IEnumerable<TransferStatusModel> values) => TagBox_ValuesChanged(values)"
ValueFieldName="StatusValue" TextFieldName="StatusName" NullText="Select status type..."
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto" aria-label="Select status type" />
</div>
</ToolbarTemplate>
</TransferGrid>
</div>
</DxTabPage>
<ToolbarTemplate>
<div>
<DxTagBox Data="@(Enum.GetValues<TransferStatusType>().ToList())" Values="@_selectedCategories"
NullText="Select status type..." ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto" aria-label="Select status type"
ValuesChanged="(IEnumerable<TransferStatusType> values) => TagBox_ValuesChanged(values)" />
<DxTabPage Text="Calendar">
<div class="d-flex flex-column mb-4 pb-2">
<DxScheduler @bind-StartDate="@StartDate"
DataStorage="@_dataStorage"
CssClass="w-100">
<DxSchedulerTimelineView Duration="@TimeSpan.FromHours(48)" CellMinWidth="80">
<Scales>
<DxSchedulerTimeScale Unit="@SchedulerTimeScaleUnit.Day" UnitCount="1"></DxSchedulerTimeScale>
<DxSchedulerTimeScale Unit="@SchedulerTimeScaleUnit.Hour" UnitCount="2"></DxSchedulerTimeScale>
</Scales>
</DxSchedulerTimelineView>
<DxSchedulerWeekView ShowWorkTimeOnly="false"></DxSchedulerWeekView>
<DxSchedulerDayView DayCount="1" ShowWorkTimeOnly="false"></DxSchedulerDayView>
</DxScheduler>
</div>
</DxTabPage>
</DxTabs>
</div>
</Animation>
</div>
@*//NE TÖRÖLD KI! - J.
<DxTagBox TData="@(TransferStatusModel)" TValue="@(TransferStatusModel)" Data="@TransferStatusModel.AllStatuses.Values" Values="@_selectedCategories"
@ref="_filterTag" ValuesChanged="(IEnumerable<TransferStatusModel> values) => TagBox_ValuesChanged(values)"
ValueFieldName="StatusValue" TextFieldName="StatusName" NullText="Select status type..."
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto" aria-label="Select status type" />*@
</div>
</ToolbarTemplate>
</TransferGrid>
</div>
</DxTabPage>
<div class=" col-12 col-xl-6">
</div>
<DxTabPage Text="Calendar">
<div class="d-flex flex-column mb-4 pb-2">
<DxScheduler @bind-StartDate="@StartDate"
DataStorage="@_dataStorage"
CssClass="w-100">
<DxSchedulerTimelineView Duration="@TimeSpan.FromHours(48)" CellMinWidth="80">
<Scales>
<DxSchedulerTimeScale Unit="@SchedulerTimeScaleUnit.Day" UnitCount="1"></DxSchedulerTimeScale>
<DxSchedulerTimeScale Unit="@SchedulerTimeScaleUnit.Hour" UnitCount="2"></DxSchedulerTimeScale>
</Scales>
</DxSchedulerTimelineView>
<DxSchedulerWeekView ShowWorkTimeOnly="false"></DxSchedulerWeekView>
<DxSchedulerDayView DayCount="1" ShowWorkTimeOnly="false"></DxSchedulerDayView>
</DxScheduler>
</div>
</DxTabPage>
</DxTabs>
</div>
</Animation>
</div>
</div>
<div class=" col-12 col-xl-6">
</div>
</div>
</div>
@code {
private LoggerClient<ManageTransfers> _logger;
private LoggerClient<ManageTransfers> _logger;
private bool _popupVisible;
private TransferGrid _gridTransfer;
private bool _popupVisible;
private TransferGrid _gridTransfer;
private DxTagBox<TransferStatusModel, TransferStatusModel> _filterTag;
private DxTagBox<TransferStatusModel, TransferStatusModel> _filterTag;
public List<string> IgnoreList =
[
"ReceiverEmailAddress",
"ReceiverFullName",
"ReceiverId",
"SenderEmailAddress",
"SenderFullName",
"SenderId",
"ContextId",
"ContextType"
];
public List<string> IgnoreList =
[
"ReceiverEmailAddress",
"ReceiverFullName",
"ReceiverId",
"SenderEmailAddress",
"SenderFullName",
"SenderId",
"ContextId",
"ContextType"
];
private static List<TransferStatusModel> _selectedCategories = TransferStatusModel.AllStatuses.Values.Where(x => x.StatusValue != TransferStatusType.Finished && x.StatusValue != TransferStatusType.UserCanceled && x.StatusValue != TransferStatusType.AdminDenied).ToList();
private string _filterText = GetFilterText(_selectedCategories.Select(x => x.StatusValue).ToList());
private static List<TransferStatusType> _selectedCategories = Enum.GetValues<TransferStatusType>().Where(x => x != TransferStatusType.Finished && x != TransferStatusType.UserCanceled && x != TransferStatusType.AdminDenied).ToList();
private string _filterText = GetFilterText(_selectedCategories);
private MessageWizardModel _messageWizardModel = new();
// NE TÖRÖLD KI! - J.
// private static List<TransferStatusModel> _selectedCategories = TransferStatusModel.AllStatuses.Values.Where(x => x.StatusValue != TransferStatusType.Finished && x.StatusValue != TransferStatusType.UserCanceled && x.StatusValue != TransferStatusType.AdminDenied).ToList();
// private string _filterText = GetFilterText(_selectedCategories.Select(x => x.StatusValue).ToList());
public List<AppointmentModel> AppointmentModels { get; set; } = null!;
private MessageWizardModel _messageWizardModel = new();
DateTime StartDate { get; set; } = DateTime.Today;
DxSchedulerDataStorage _dataStorage = new();
public List<AppointmentModel> AppointmentModels { get; set; } = null!;
DateTime StartDate { get; set; } = DateTime.Today;
DxSchedulerDataStorage _dataStorage = new();
void SendMail(Transfer item)
{
_logger.Info($"Preparing mail to {item.ContactEmail}, {item.Id}");
_messageWizardModel.Subject = $"[#{item.OrderId}] New message regarding your transfer";
_messageWizardModel.ReceiverId = item.UserId;
_messageWizardModel.ContextId = item.Id;
_messageWizardModel.ContextType = MessageContextType.Transfer;
_messageWizardModel.SenderId = TiamConstClient.SysAccounts["SystemEmailSender"];
_messageWizardModel.SenderEmailAddress = TiamConstClient.SystemEmailAddress;
_messageWizardModel.ReceiverEmailAddress = item.ContactEmail;
_messageWizardModel.ReceiverFullName = item.FullName;
_popupVisible = true;
}
void CancelCreateClick()
{
_popupVisible = false;
}
void EulaPopupClosed()
{
//cancel clicked
}
void EulaPopupClosing(PopupClosingEventArgs args)
{
//myModel = new TransferWizardModel();
_messageWizardModel = new MessageWizardModel();
}
//-----------------------------------------------------------------------------------
void SendMail(Transfer item)
{
_logger.Info($"Preparing mail to {item.ContactEmail}, {item.Id}");
_messageWizardModel.Subject = $"[#{item.OrderId}] New message regarding your transfer";
_messageWizardModel.ReceiverId = item.UserId;
_messageWizardModel.ContextId = item.Id;
_messageWizardModel.ContextType = MessageContextType.Transfer;
_messageWizardModel.SenderId = TiamConstClient.SysAccounts["SystemEmailSender"];
_messageWizardModel.SenderEmailAddress = TiamConstClient.SystemEmailAddress;
_messageWizardModel.ReceiverEmailAddress = item.ContactEmail;
_messageWizardModel.ReceiverFullName = item.FullName;
_popupVisible = true;
}
public async Task SubmitForm(object result)
{
var messageModel = (result as MessageWizardModel)!;
_logger.Info(messageModel.Content);
var email = await wizardProcessor.ProcessWizardAsync<MessageWizardModel>(result.GetType(), messageModel);
_logger.Info($"Submitted nested form: {result.GetType().FullName}");
CancelCreateClick();
}
void CancelCreateClick()
{
void Grid_CustomizeElement(GridCustomizeElementEventArgs e)
{
try
{
if (e.ElementType == GridElementType.HeaderCell)
{
e.Style = "background-color: rgba(0, 0, 0, 0.08)";
e.CssClass = "header-bold";
}
_popupVisible = false;
}
if (e.ElementType != GridElementType.DataRow) return;
void EulaPopupClosed()
{
//cancel clicked
var transferStatus = e.Grid?.GetRowValue(e.VisibleIndex, "TransferStatusType");
if (transferStatus == null) return;
}
var transferStatusByte = (byte)transferStatus;
void EulaPopupClosing(PopupClosingEventArgs args)
{
//myModel = new TransferWizardModel();
_messageWizardModel = new MessageWizardModel();
}
switch (transferStatusByte)
{
case 5:
e.CssClass = "bg-important";
break;
case > 5 and < 35:
e.CssClass = "bg-attention";
break;
case 35:
e.CssClass = "bg-finished";
break;
case > 35:
e.CssClass = "bg-cancel";
break;
}
}
catch (Exception ex)
{
_logger.Error($"Grid_CustomizeElement; {ex.Message}", ex);
}
}
//-----------------------------------------------------------------------------------
void Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e)
{
if (!e.IsNew) return;
var transferEditModel = (Transfer)e.EditModel; //TODO not valid cast
transferEditModel.Id = Guid.NewGuid();
transferEditModel.ToAddress = "Where to?";
transferEditModel.FromAddress = "From where?";
transferEditModel.Appointment = DateTime.UtcNow.AddDays(3);
transferEditModel.PassengerCount = 1;
transferEditModel.FirstName = "John";
transferEditModel.LastName = "Doe";
transferEditModel.ContactPhone = "+00000000000";
transferEditModel.ContactEmail = "your@email.address";
}
private static string GetFilterText(ICollection<TransferStatusType> selectedTransferStatuses)
=> selectedTransferStatuses.Count == 0 ? string.Empty : CriteriaOperator.FromLambda<Transfer>(t => selectedTransferStatuses.Contains(t.TransferStatusType)).ToString();
void TagBox_ValuesChanged(IEnumerable<TransferStatusType> newSelectedCategories)
{
var filterText = string.Empty;
InOperator? filterCriteria = null;
_selectedCategories = newSelectedCategories.ToList();
if (_selectedCategories.Count > 0)
{
filterCriteria = new InOperator(nameof(Transfer.TransferStatusType), _selectedCategories);
filterText = GetFilterText(_selectedCategories);
}
_filterText = filterText;
_gridTransfer.SetFieldFilterCriteria(nameof(Transfer.TransferStatusType), filterCriteria);
}
// NE TÖRÖLD KI! - J.
// void TagBox_ValuesChanged(IEnumerable<TransferStatusModel> newSelectedCategories)
// {
// var filterText = string.Empty;
// InOperator? filterCriteria = null;
// _selectedCategories = newSelectedCategories.ToList();
// //_selectedCategories.Clear();
// //_selectedCategories.AddRange(newSelectedCategories);
// if (_selectedCategories.Count > 0)
// {
// filterCriteria = new InOperator(nameof(Transfer.TransferStatusType), _selectedCategories.Select(c => c.StatusValue));
// filterText = GetFilterText(_selectedCategories.Select(x => (TransferStatusType)x.StatusValue).ToList());
// }
// _filterText = filterText;
// _gridTransfer.SetFieldFilterCriteria(nameof(Transfer.TransferStatusType), filterCriteria);
// }
private void DataSourceChanged(IList<Transfer> transfers)
{
_logger.Info("DataSourceChanged called");
InitializeAppointments(transfers);
if (_selectedCategories.Count > 0)
TagBox_ValuesChanged(_selectedCategories);
// if(!SelectedCategories.Any())
// SelectedCategories = [Statuses.FirstOrDefault(x => x.StatusValue == (byte)TransferStatusType.Finished)!];
// var filterTransferStatusType = Statuses.FirstOrDefault(x => x.StatusValue == (byte)TransferStatusType.Finished)!;
// if (SelectedCategories.All(x => x.StatusValue != filterTransferStatusType.StatusValue))
// SelectedCategories.Add(filterTransferStatusType);
}
private void DataSourceItemChanging(GridDataItemChangingEventArgs<Transfer> args)
{
_logger.Info("DataSourceItemChanging called");
}
private void DataSourceItemChanged(GridDataItemChangedEventArgs<Transfer> args)
{
_logger.Info("DataSourceItemChanged called");
AppointmentModels.UpdateCollection(CreateAppointmentModel(args.DataItem), args.TrackingState == TrackingState.Remove);
}
private void DataItemSaving(GridEditModelSavingEventArgs e)
{
_logger.Info("DataItemSaving called");
}
private void DataItemDeleting(GridDataItemDeletingEventArgs e)
{
_logger.Info($"DataItemDeleting OnItemDeleting");
}
protected override Task OnInitializedAsync()
{
_logger = new LoggerClient<ManageTransfers>(_logWriters.ToArray());
//await AdminSignalRClient.GetAllCarsByProductIdAsync(TiamConstClient.TransferProductId, _cars, StateHasChanged);
//await base.OnInitializedAsync();
return base.OnInitializedAsync();
}
private void InitializeAppointments(ICollection<Transfer> transferDataList)
{
_logger.Info("InitializeAppointments called");
AppointmentModels = new List<AppointmentModel>(transferDataList.Count);
foreach (var transfer in transferDataList)
{
// var bnm = DataStorage.CreateAppointmentItem();
// bnm.Start = transfer.Appointment;
// bnm.Description = $"{transfer.FullName}, {transfer.ToAddress}";
// bnm.Location = transfer.FromAddress;
// bnm.Subject = "Simple transfer";
AppointmentModels.Add(CreateAppointmentModel(transfer));
}
_dataStorage = new DxSchedulerDataStorage
{
AppointmentMappings = new DxSchedulerAppointmentMappings()
{
Type = "AppointmentType",
Start = "StartDate",
End = "EndDate",
Subject = "Caption",
AllDay = "AllDay",
Location = "Location",
Description = "Description",
LabelId = "Label",
StatusId = "Status",
RecurrenceInfo = "Recurrence"
},
AppointmentsSource = AppointmentModels
};
}
public AppointmentModel CreateAppointmentModel(Transfer transfer)
{
return new AppointmentModel { Id = transfer.Id, StartDate = transfer.Appointment, EndDate = transfer.Appointment.AddMinutes(30), Description = $"{transfer.FullName}, {transfer.ToAddress}", Location = transfer.FromAddress, Caption = "Simple transfer" };
}
void ColumnChooserButton_Click()
{
_gridTransfer.ShowColumnChooser();
}
public async Task SubmitForm(object result)
{
var messageModel = (result as MessageWizardModel)!;
_logger.Info(messageModel.Content);
var email = await wizardProcessor.ProcessWizardAsync<MessageWizardModel>(result.GetType(), messageModel);
_logger.Info($"Submitted nested form: {result.GetType().FullName}");
CancelCreateClick();
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
//_gridTransfer.ExpandDetailRow(0);
}
}
void Grid_CustomizeElement(GridCustomizeElementEventArgs e)
{
try
{
if (e.ElementType == GridElementType.HeaderCell)
{
e.Style = "background-color: rgba(0, 0, 0, 0.08)";
e.CssClass = "header-bold";
}
private void OnSelectedDataItemChanged(object selectedRow)
{
if (selectedRow is not Transfer selectedTransfer) return;
if (e.ElementType != GridElementType.DataRow) return;
RefreshTransferToDriversData(selectedTransfer, () => { _gridTransfer.Reload(); });
}
var transferStatus = e.Grid?.GetRowValue(e.VisibleIndex, "TransferStatusType");
if (transferStatus == null) return;
private void RefreshTransferToDriversData(Transfer? transfer, Action? callback = null)
{
try
{
if (transfer == null || transfer.TransferToDrivers.Count != 0 || transfer.TransferStatusType < TransferStatusType.AssignedToDriver)
return;
var transferStatusByte = (byte)transferStatus;
AdminSignalRClient.GetByIdAsync<List<TransferToDriver>?>(SignalRTags.GetTransferDriversByTransferId, x =>
{
if (x?.ResponseData == null) return Task.CompletedTask;
switch (transferStatusByte)
{
case 5:
e.CssClass = "bg-important";
break;
case > 5 and < 35:
e.CssClass = "bg-attention";
break;
case 35:
e.CssClass = "bg-finished";
break;
case > 35:
e.CssClass = "bg-cancel";
break;
}
}
catch (Exception ex)
{
_logger.Error($"Grid_CustomizeElement; {ex.Message}", ex);
}
}
transfer.TransferToDrivers.UpdateCollection<TransferToDriver>(x.ResponseData, false);
callback?.Invoke();
void Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e)
{
if (!e.IsNew) return;
var transferEditModel = (Transfer)e.EditModel; //TODO not valid cast
transferEditModel.Id = Guid.NewGuid();
transferEditModel.ToAddress = "Where to?";
transferEditModel.FromAddress = "From where?";
transferEditModel.Appointment = DateTime.UtcNow.AddDays(3);
transferEditModel.PassengerCount = 1;
transferEditModel.FirstName = "John";
transferEditModel.LastName = "Doe";
transferEditModel.ContactPhone = "+00000000000";
transferEditModel.ContactEmail = "your@email.address";
}
private static string GetFilterText(ICollection<TransferStatusType> selectedTransferStatuses)
=> selectedTransferStatuses.Count == 0 ? string.Empty : CriteriaOperator.FromLambda<Transfer>(t => selectedTransferStatuses.Contains(t.TransferStatusType)).ToString();
void TagBox_ValuesChanged(IEnumerable<TransferStatusModel> newSelectedCategories)
{
var filterText = string.Empty;
InOperator? filterCriteria = null;
_selectedCategories = newSelectedCategories.ToList();
if (_selectedCategories.Count > 0)
{
filterCriteria = new InOperator("TransferStatusType", _selectedCategories.Select(c => c.StatusValue));
filterText = GetFilterText(_selectedCategories.Select(x => (TransferStatusType)x.StatusValue).ToList());
}
_filterText = filterText;
_gridTransfer.SetFieldFilterCriteria("TransferStatusType", filterCriteria);
}
private void DataSourceChanged(IList<Transfer> transfers)
{
_logger.Info("DataSourceChanged called");
InitializeAppointments(transfers);
if (_selectedCategories.Count > 0)
TagBox_ValuesChanged(_selectedCategories);
// if(!SelectedCategories.Any())
// SelectedCategories = [Statuses.FirstOrDefault(x => x.StatusValue == (byte)TransferStatusType.Finished)!];
// var filterTransferStatusType = Statuses.FirstOrDefault(x => x.StatusValue == (byte)TransferStatusType.Finished)!;
// if (SelectedCategories.All(x => x.StatusValue != filterTransferStatusType.StatusValue))
// SelectedCategories.Add(filterTransferStatusType);
}
private void DataSourceItemChanging(GridDataItemChangingEventArgs<Transfer> args)
{
_logger.Info("DataSourceItemChanging called");
}
private void DataSourceItemChanged(GridDataItemChangedEventArgs<Transfer> args)
{
_logger.Info("DataSourceItemChanged called");
AppointmentModels.UpdateCollection(CreateAppointmentModel(args.DataItem), args.TrackingState == TrackingState.Remove);
}
private void DataItemSaving(GridEditModelSavingEventArgs e)
{
_logger.Info("DataItemSaving called");
}
private void DataItemDeleting(GridDataItemDeletingEventArgs e)
{
_logger.Info($"DataItemDeleting OnItemDeleting");
}
protected override Task OnInitializedAsync()
{
_logger = new LoggerClient<ManageTransfers>(_logWriters.ToArray());
return base.OnInitializedAsync();
}
private void InitializeAppointments(ICollection<Transfer> transferDataList)
{
_logger.Info("InitializeAppointments called");
AppointmentModels = new List<AppointmentModel>(transferDataList.Count);
foreach (var transfer in transferDataList)
{
// var bnm = DataStorage.CreateAppointmentItem();
// bnm.Start = transfer.Appointment;
// bnm.Description = $"{transfer.FullName}, {transfer.ToAddress}";
// bnm.Location = transfer.FromAddress;
// bnm.Subject = "Simple transfer";
AppointmentModels.Add(CreateAppointmentModel(transfer));
}
_dataStorage = new DxSchedulerDataStorage
{
AppointmentMappings = new DxSchedulerAppointmentMappings()
{
Type = "AppointmentType",
Start = "StartDate",
End = "EndDate",
Subject = "Caption",
AllDay = "AllDay",
Location = "Location",
Description = "Description",
LabelId = "Label",
StatusId = "Status",
RecurrenceInfo = "Recurrence"
},
AppointmentsSource = AppointmentModels
};
}
public AppointmentModel CreateAppointmentModel(Transfer transfer)
{
return new AppointmentModel { Id = transfer.Id, StartDate = transfer.Appointment, EndDate = transfer.Appointment.AddMinutes(30), Description = $"{transfer.FullName}, {transfer.ToAddress}", Location = transfer.FromAddress, Caption = "Simple transfer" };
}
void ColumnChooserButton_Click()
{
_gridTransfer.ShowColumnChooser();
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
//_gridTransfer.ExpandDetailRow(0);
}
}
return Task.CompletedTask;
}, transfer.Id).Forget();
}
catch (Exception ex)
{
_logger.Error($"RefreshTransferToDriversData error; transferId: {transfer?.Id}", ex);
}
}
}

View File

@ -27,14 +27,15 @@
@inject AdminSignalRClient AdminSignalRClient;
@inject ISessionServiceClient sessionService
@inject IComponentUpdateService ComponentUpdateService
@inject ITransferDataService transferDataService
<MessageDetailGrid CssClass="my-grid" @ref="_messageGrid"
Logger="_logger"
SignalRClient="AdminSignalRClient"
GetAllMessageTag="GetAllMessageTag"
ContextIds="@(ContextId.IsNullOrEmpty() ? throw new InvalidDataException($"ContextId.IsNullOrEmpty(); ContextId: {ContextId}") : [ContextId.Value])"
CustomizeElement="CustomizeElement"
ShowFilterRow="ShowFilterRow">
Logger="_logger"
SignalRClient="AdminSignalRClient"
GetAllMessageTag="GetAllMessageTag"
ContextIds="@(ContextId.IsNullOrEmpty() ? throw new InvalidDataException($"ContextId.IsNullOrEmpty(); ContextId: {ContextId}") : [ContextId.Value])"
CustomizeElement="CustomizeElement"
ShowFilterRow="ShowFilterRow">
<Columns>
<DxGridCommandColumn Width="135" MinWidth="135" Visible="AcDomain.IsDeveloperVersion" DeleteButtonVisible="AcDomain.IsDeveloperVersion" EditButtonVisible="AcDomain.IsDeveloperVersion" FixedPosition="GridColumnFixedPosition.Left" />
<DxGridDataColumn FieldName="SenderId" Caption=" " Width="30px" ShowInColumnChooser="AcDomain.IsDeveloperVersion" DisplayFormat="N" AllowSort="false">
@ -163,10 +164,24 @@
private Guid? myUserId;
protected override void OnInitialized()
protected override async Task OnInitializedAsync()
{
_logger = new LoggerClient<MessageDetailGridComponent>(LogWriters.ToArray());
myUserId = _sessionService.User.UserId;
if(sessionService.User != null)
{
myUserId = _sessionService.User.UserId;
}
else
{
if(ContextId != null)
{
//should be transfer because in any other way, the user must be logged in
myUserId = Guid.Empty; //TODO get userId by transfer
var transfer = await AdminSignalRClient.GetTransferById((Guid)ContextId);
myUserId = transfer.UserId;
}
}
}
private void CustomizeElement(GridCustomizeElementEventArgs e)

View File

@ -0,0 +1,240 @@
@page "/sysadmin/manage-tours"
@using System.ComponentModel.DataAnnotations
@using TIAM.Entities.Transfers
@using TIAMWebApp.Shared.Application.Interfaces
@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Services
@using TIAMSharedUI.Shared
@inject ITransferDataService TransferDataService
@inject TourService TourService
@inject NavigationManager Navigation
@layout AdminLayout
<PageTitle>Manage Tours</PageTitle>
<h1 class="text-center m-4">Manage Tours</h1>
<div class="container">
<div class="mb-4">
<h4>Create New Tour</h4>
<EditForm Model="@newTour" OnValidSubmit="HandleSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-3">
<label>Select Transfer Destination</label>
<InputSelect @bind-Value="newTour.TransferDestinationId" class="form-control">
<option value="">-- Select --</option>
@foreach (var dest in TransferDestinations)
{
<option value="@dest.Id">@dest.Name (@dest.AddressString)</option>
}
</InputSelect>
</div>
<div class="mb-3">
<label>Tour name</label>
<InputTextArea @bind-Value="newTour.Name" class="form-control" />
</div>
<div class="mb-3">
<label>Description</label>
<InputTextArea @bind-Value="newTour.Description" class="form-control" />
</div>
<div class="mb-3">
<label>Cover Photo</label>
<InputFile OnChange="HandleFileChange" />
@if (!string.IsNullOrEmpty(UploadStatus))
{
<div class="text-muted mt-1">@UploadStatus</div>
}
</div>
<button class="btn btn-primary me-2" type="submit">
@(IsEditing ? "Update Tour" : "Save Tour")
</button>
@if (IsEditing)
{
<button class="btn btn-secondary" type="button" @onclick="CancelEdit">Cancel</button>
}
</EditForm>
</div>
<hr />
<div>
<h4>Existing Tours</h4>
@if (Tours.Any())
{
<ul class="list-group">
@foreach (var tour in Tours)
{
var dest = TransferDestinations.FirstOrDefault(d => d.Id == tour.TransferDestinationId);
<li class="list-group-item d-flex justify-content-between align-items-center">
<img src="@tour.CoverImageUrl" style="max-height: 100px;"/>
<span>
<strong>@tour?.Title</strong> — @tour.FancyDescription
</span>
<button class="btn btn-sm btn-secondary me-2" @onclick="() => EditTour(tour)">Edit</button>
<button class="btn btn-sm btn-danger" @onclick="() => DeleteTourAsync(tour.Id)">Delete</button>
</li>
}
</ul>
}
else
{
<p>No tours available.</p>
}
</div>
</div>
@code {
private List<TransferDestination> TransferDestinations = [];
private List<TourInfo> Tours = [];
private TourFormModel newTour = new();
private IBrowserFile? uploadedFile;
private string UploadStatus = string.Empty;
private bool IsEditing = false;
private Guid? EditingTourId = null;
protected override async Task OnInitializedAsync()
{
TransferDestinations = (await TransferDataService.GetDestinationsAsync()).ToList();
Tours = (await TourService.GetAllAsync()).ToList();
}
private void EditTour(TourInfo tour)
{
newTour = new TourFormModel
{
TransferDestinationId = tour.TransferDestinationId,
Name = tour.Title,
Description = tour.FancyDescription,
ImageBytes = null,
ImageFileName = null
};
IsEditing = true;
EditingTourId = tour.Id;
UploadStatus = string.Empty;
}
private void CancelEdit()
{
newTour = new TourFormModel();
uploadedFile = null;
IsEditing = false;
EditingTourId = null;
UploadStatus = string.Empty;
}
// private async Task SaveTourAsync()
// {
// if (uploadedFile is not null)
// {
// using var stream = uploadedFile.OpenReadStream(maxAllowedSize: 5 * 1024 * 1024);
// using var ms = new MemoryStream();
// await stream.CopyToAsync(ms);
// newTour.ImageBytes = ms.ToArray();
// newTour.ImageFileName = uploadedFile.Name;
// }
// TourInfo tourToCreate = new TourInfo();
// tourToCreate.TransferDestinationId = newTour.TransferDestinationId;
// tourToCreate.FancyDescription = newTour.Description;
// tourToCreate.Title = newTour.Name;
// tourToCreate.CoverImageUrl = "";
// if (tourToCreate.TransferDestinationId == Guid.Empty)
// {
// throw new InvalidOperationException("Transfer Destination must be selected.");
// }
// await TourService.CreateAsync(tourToCreate, uploadedFile);
// newTour = new();
// uploadedFile = null;
// UploadStatus = string.Empty;
// Tours = (await TourService.GetAllAsync()).ToList();
// }
private async Task HandleSubmit()
{
if (uploadedFile is not null)
{
using var stream = uploadedFile.OpenReadStream(maxAllowedSize: 5 * 1024 * 1024);
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
newTour.ImageBytes = ms.ToArray();
newTour.ImageFileName = uploadedFile.Name;
}
if (IsEditing && EditingTourId.HasValue)
{
var updatedTour = new TourInfo
{
Id = EditingTourId.Value,
TransferDestinationId = newTour.TransferDestinationId,
Title = newTour.Name,
FancyDescription = newTour.Description,
CoverImageUrl = "" // assume your service handles image URL logic
};
await TourService.UpdateAsync(updatedTour, uploadedFile);
}
else
{
var tourToCreate = new TourInfo
{
TransferDestinationId = newTour.TransferDestinationId,
Title = newTour.Name,
FancyDescription = newTour.Description,
CoverImageUrl = newTour.ImageFileName
};
await TourService.CreateAsync(tourToCreate, uploadedFile);
}
// Reset form
newTour = new TourFormModel();
uploadedFile = null;
IsEditing = false;
EditingTourId = null;
UploadStatus = string.Empty;
Tours = (await TourService.GetAllAsync()).ToList();
}
private void HandleFileChange(InputFileChangeEventArgs e)
{
uploadedFile = e.File;
UploadStatus = $"Selected: {uploadedFile.Name}";
}
private async Task DeleteTourAsync(Guid id)
{
await TourService.DeleteAsync(id);
Tours = (await TourService.GetAllAsync()).ToList();
}
public class TourFormModel
{
[Required]
public Guid TransferDestinationId { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Tour name cannot exceed 100 characters.")]
public string Name { get; set; } = string.Empty;
public string? Description { get; set; }
public byte[]? ImageBytes { get; set; }
public string? ImageFileName { get; set; }
}
}

View File

@ -135,7 +135,7 @@
newDestination.Id = Guid.NewGuid();
newDestination.Name = "Destination name";
newDestination.Description = "Type some description here";
newDestination.AddressString = "The address of the destination";
newDestination.AddressString = $"The address of: {newDestination.Name}";
Guid addressId = Guid.NewGuid();
newDestination.Address = new Address();
newDestination.Address.Id = addressId;

View File

@ -18,7 +18,7 @@
<div class="page">
<TiamErrorBoundaryComponent LoggerCategory="AdminLayout" OnError="HandleError">
<AppLaunchComponent />
<AdminNavMenu />
<NavHelperComponent />

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,11 @@
 <!-- footer -->
<footer class="pt-lg-10 pt-5 footer bg-white">
<footer class="pt-lg-10 pt-5 footer bg-light">
<div class="container">
<div class="row">
<div class="col-lg-4 col-md-6 col-12">
<!-- about company -->
<div class="mb-4">
<img src="../assets/images/brand/logo/logo.svg" alt="" class="logo-inverse ">
<img src="_content/TIAMSharedUI/images/logo_wide.png" alt="" class="logo-inverse ">
<div class="mt-4">
<p>
Geek is feature-rich components and beautifully Bootstrap UIKit for developers, built with bootstrap

View File

@ -6,8 +6,6 @@ namespace TIAMSharedUI.Shared.Components.Grids;
public class TransferGrid : TiamGrid<Transfer>
{
public TransferGrid() : base()
{
GetAllMessageTag = SignalRTags.GetTransfersByFilterText;//SignalRTags.GetTransfers;

View File

@ -23,9 +23,38 @@
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="explore-the-region">
@localizer.GetString("NavMenu.ExploreTheRegion")
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="signature-ride-packages">
@localizer.GetString("NavMenu.SignatureRidePackages")
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="how-it-works">
@localizer.GetString("NavMenu.HowItWorks")
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="about">
@localizer.GetString("NavMenu.About")
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="contact">
@localizer.GetString("NavMenu.Contact")
</NavLink>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="transfer">
@localizer.GetString("NavMenu.Transfer")
@localizer.GetString("NavMenu.BookNow")
</NavLink>
</li>
@ -50,17 +79,12 @@
<li class="nav-item">
<NavLink class="nav-link" href="about">
@localizer.GetString("NavMenu.About")
</NavLink>
</li>
<li class="nav-item">
@* <li class="nav-item">
<NavLink class="nav-link" href="roadmap">
@localizer.GetString("NavMenu.Roadmap")
</NavLink>
</li>
</li> *@
</ul>
<ul class="nav navbar-nav navbar-right">

View File

@ -1,6 +1,7 @@
.navbar {
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
background-color: rgba(255, 255, 255, 0.7)
}
.navbar-toggler {

View File

@ -0,0 +1,84 @@

@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Services
@inject TourService TourService
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
<div class="container">
<section class="game-section" style="max-width: 100%; overflow-x:hidden">
<div class="text-center">
<h1>Tours</h1>
<h2>Please select!</h2>
</div>
<div class="owl-carousel custom-carousel owl-theme">
@if (Tours != null && Tours.Any()) // Only render the loop if Tours has data
{
foreach (var item in Tours)
{
<div class="item" style="background-image: url(@item.CoverImageUrl);">
<div class="item-desc" style="height: 100%; background-color: rgba(0,0,0,0.3);">
<p style="padding-top:70px">@item.Created</p>
<p>@item.FancyDescription</p>
@* <p>@item.TransferDestinationId</p> *@
<div>
<button class="btn btn-primary mt-auto" @onclick="@( ()=> Book(item.TransferDestinationId, 1))">1-3 passengers</button>
<button class="btn btn-primary mt-auto" @onclick="@( ()=> Book(item.TransferDestinationId, 2))">4-6 passengers</button>
<button class="btn btn-primary mt-auto" @onclick="@( ()=> Book(item.TransferDestinationId, 3))">7-8 passengers</button>
</div>
<div class="glass" style="position: absolute; top:0px; left:0px; padding:10px; width:100%">
<h4>@item.Title</h4>
</div>
</div>
</div>
}
}
else
{
<p>Loading tours...</p>
}
</div>
</section>
</div>
<script>
function initializeOwlCarousel() {
console.log("Initializing Owl Carousel..."); // For debugging
$(".custom-carousel").owlCarousel({
autoWidth: true,
loop: true
});
// Ensure this runs only once per initialization
$(document).ready(function () { // This ready might not be needed if called after DOM update
$(".custom-carousel .item").off("click").on("click", function () { // Use .off().on() to prevent multiple handlers
$(".custom-carousel .item").not($(this)).removeClass("active");
$(this).toggleClass("active");
});
});
}
</script>
@code {
public List<TourInfo> Tours = new List<TourInfo>();
private bool _owlCarouselInitialized = false;
protected override async Task OnInitializedAsync()
{
Tours = (await TourService.GetAllAsync()).ToList();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Only initialize Owl Carousel once, after data is loaded and rendered
if (Tours != null && Tours.Any() && !_owlCarouselInitialized)
{
await JSRuntime.InvokeVoidAsync("initializeOwlCarousel");
_owlCarouselInitialized = true; // Set flag to true after successful initialization
}
}
private void Book(Guid id, int category)
{
NavigationManager.NavigateTo($"/book-a-tour/{id.ToString()}/{category}");
}
}

View File

@ -0,0 +1,288 @@

/******* Common Element CSS Start ******/
body {
font-family: "Roboto", sans-serif;
font-size: 16px;
}
.clear {
clear: both;
}
img {
max-width: 100%;
border: 0px;
}
ul,
ol {
list-style: none;
}
a {
text-decoration: none;
color: inherit;
outline: none;
transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
}
a:focus,
a:active,
a:visited,
a:hover {
text-decoration: none;
outline: none;
}
a:hover {
color: #e73700;
}
h2 {
margin-bottom: 48px;
padding-bottom: 16px;
font-size: 20px;
line-height: 28px;
font-weight: 700;
position: relative;
text-transform: capitalize;
}
h3 {
margin: 0 0 10px;
font-size: 28px;
line-height: 36px;
}
button {
outline: none !important;
}
/******* Common Element CSS End *********/
/* -------- title style ------- */
.line-title {
position: relative;
width: 400px;
}
.line-title::before,
.line-title::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
height: 4px;
border-radius: 2px;
}
.line-title::before {
width: 100%;
background: #f2f2f2;
}
.line-title::after {
width: 32px;
background: #e73700;
}
/******* Middle section CSS Start ******/
/* -------- Landing page ------- */
.game-section {
/*padding: 5px 50px;*/
}
.game-section .owl-stage {
margin: 15px 0;
display: flex;
display: -webkit-flex;
}
.game-section .item {
margin: 0 15px 60px;
width: 320px;
height: 400px;
display: flex;
display: -webkit-flex;
align-items: flex-end;
-webkit-align-items: flex-end;
background: #343434 no-repeat center center / cover;
border-radius: 16px;
overflow: hidden;
position: relative;
transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
cursor: pointer;
box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.57 );
}
.game-section .item.active {
width: 500px;
box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.57 );
-webkit-box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.57 );
}
.game-section .item:after {
content: "";
display: block;
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
}
.game-section .item-desc {
padding: 0 24px 12px;
color: #fff;
position: relative;
z-index: 1;
overflow: hidden;
transform: translateY(calc(100% - 54px));
-webkit-transform: translateY(calc(100% - 54px));
transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
}
.game-section .item.active .item-desc {
transform: none;
-webkit-transform: none;
}
.game-section .item-desc p {
opacity: 0;
-webkit-transform: translateY(32px);
transform: translateY(32px);
transition: all 0.4s ease-in-out 0.2s;
-webkit-transition: all 0.4s ease-in-out 0.2s;
}
.game-section .item.active .item-desc p {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
.game-section .owl-theme.custom-carousel .owl-dots {
margin-top: -20px;
position: relative;
z-index: 5;
}
/******** Middle section CSS End *******/
/***** responsive css Start ******/
@media (min-width: 992px) and (max-width: 1199px) {
h2 {
margin-bottom: 32px;
}
h3 {
margin: 0 0 8px;
font-size: 24px;
line-height: 32px;
}
/* -------- Landing page ------- */
.game-section {
/*padding: 50px 5px;*/
}
.game-section .item {
margin: 0 12px 60px;
width: 260px;
height: 360px;
}
.game-section .item.active {
width: 400px;
}
.game-section .item-desc {
transform: translateY(calc(100% - 46px));
-webkit-transform: translateY(calc(100% - 46px));
}
}
@media (min-width: 768px) and (max-width: 991px) {
h2 {
margin-bottom: 32px;
}
h3 {
margin: 0 0 8px;
font-size: 24px;
line-height: 32px;
}
.line-title {
width: 330px;
}
/* -------- Landing page ------- */
.game-section {
/*padding: 50px 5px 40px;*/
}
.game-section .item {
margin: 0 12px 60px;
width: 240px;
height: 330px;
}
.game-section .item.active {
width: 360px;
}
.game-section .item-desc {
transform: translateY(calc(100% - 42px));
-webkit-transform: translateY(calc(100% - 42px));
}
}
@media (max-width: 767px) {
body {
font-size: 14px;
}
h2 {
margin-bottom: 20px;
}
h3 {
margin: 0 0 8px;
font-size: 19px;
line-height: 24px;
}
.line-title {
width: 250px;
}
/* -------- Landing page ------- */
.game-section {
padding: 30px 15px 20px;
}
.game-section .item {
margin: 0 10px 40px;
width: 200px;
height: 280px;
}
.game-section .item.active {
width: 270px;
box-shadow: 6px 10px 10px rgba(0, 0, 0, 0.25);
-webkit-box-shadow: 6px 10px 10px rgba(0, 0, 0, 0.25);
}
.game-section .item-desc {
padding: 0 14px 5px;
transform: translateY(calc(100% - 42px));
-webkit-transform: translateY(calc(100% - 42px));
}
}

View File

@ -1,14 +1,24 @@
@using BlazorAnimation
@using TIAMWebApp.Shared.Application.Models.ClientSide.UI
<header style="padding-bottom: @PBottom;">
<header style="padding-bottom: @PBottom;" class="bg-light">
<div id="owl-demo" class="owl-carousel owl-theme" style="/* position:absolute; */ z-index: 1;">
@{
foreach (var slider in SliderItems)
{
<div class="item d-flex align-items-center" style="height: @Height;">
<img src="@slider.ImageUrl" class="my-auto" alt="@slider.Title">
<div class="item d-flex align-items-center" style="height: @Height; background-image : url('@slider.ImageUrl'); background-size:cover; background-position:center; background-color: rgba(0, 0, 0, 0.6); background-blend-mode: overlay;">
<div class="container">
<div class="row">
<div class="col-6 col-sm-12 text-white">
<h1>@slider.Title</h1>
<p>@slider.Subtitle</p>
<a href="@slider.ButtonUrl" class="btn btn-primary">@slider.ButtonText</a>
</div>
</div>
</div>
</div>
}
}

View File

@ -19,6 +19,7 @@
<NavMenu />
</div-->
@* <main class="bg-gradient"> *@
<main>
<article class="content">
<CascadingValue Value=PopupMessageBox>

View File

@ -12,13 +12,14 @@
@inject NavigationManager NavigationManager
@inject IEnumerable<IAcLogWriterClientBase> LogWriters
@inject IJSRuntime jsRuntime
@inject IComponentUpdateService componentUpdateService
<div class="w-100" style="height:40px; position:fixed; z-index: 10000;">
<DxMenu CssClass="my-menu" SizeMode="SizeMode.Medium" Title="Tour I Am" ItemsPosition="ItemPosition.End" CollapseItemsToHamburgerMenu="true"
Orientation="Orientation"
DisplayMode="DisplayMode"
HamburgerButtonPosition="MenuHamburgerButtonPosition.Right">
Orientation="Orientation"
DisplayMode="DisplayMode"
HamburgerButtonPosition="MenuHamburgerButtonPosition.Right">
<TitleTemplate>
@{
if (_isMobile)
@ -32,29 +33,29 @@
@if (IsSysAdmin)
{
<DxToolbarItem Name="Transfers"
BeginGroup="true"
IconCssClass="fa-solid fa-face-smile"
Tooltip="Transfers"
Alignment="ToolbarItemAlignment.Right"
Click="() => NavigationManager.NavigateTo(url1)" />
BeginGroup="true"
IconCssClass="fa-solid fa-face-smile"
Tooltip="Transfers"
Alignment="ToolbarItemAlignment.Right"
Click="() => NavigationManager.NavigateTo(url1)" />
}
@if (IsDriver)
{
<DxToolbarItem Name="Transfers"
BeginGroup="true"
IconCssClass="fa-solid fa-taxi"
Tooltip="My tasks"
Alignment="ToolbarItemAlignment.Right"
Click="() => NavigationManager.NavigateTo(url2)" />
BeginGroup="true"
IconCssClass="fa-solid fa-taxi"
Tooltip="My tasks"
Alignment="ToolbarItemAlignment.Right"
Click="() => NavigationManager.NavigateTo(url2)" />
}
<DxToolbarItem Name="Messages"
BeginGroup="true"
IconCssClass="fa-solid fa-envelope"
Tooltip="Messages"
Alignment="ToolbarItemAlignment.Right"
Click="() => NavigationManager.NavigateTo(url3)" />
BeginGroup="true"
IconCssClass="fa-solid fa-envelope"
Tooltip="Messages"
Alignment="ToolbarItemAlignment.Right"
Click="() => NavigationManager.NavigateTo(url3)" />
</Items>
</DxToolbar>
}
@ -97,6 +98,8 @@
<DxMenuItem NavigateUrl="sysadmin/userproductmappings" Text="Permissions" />
<DxMenuItem NavigateUrl="sysadmin/users" Text="Users" />
<DxMenuItem NavigateUrl="sysadmin/blogs" Text="Blog" />
<DxMenuItem NavigateUrl="sysadmin/manage-tours" Text="Tours" />
</Items>
</DxMenuItem>
@ -107,11 +110,11 @@
</DxMenuItem>
<!--DxMenuItem Text="HotelAdmin" IconCssClass="menu-icon-support menu-icon">
<Items>
<DxMenuItem NavigateUrl="user/hoteladmin/" Text="Dashboard" />
<DxMenuItem NavigateUrl="user/createAndManageTransfer" Text="Transfers" />
<DxMenuItem NavigateUrl="user/serviceprovider/5453-a87f77787d-khj899" Text="Manage hotel" />
</Items>
<Items>
<DxMenuItem NavigateUrl="user/hoteladmin/" Text="Dashboard" />
<DxMenuItem NavigateUrl="user/createAndManageTransfer" Text="Transfers" />
<DxMenuItem NavigateUrl="user/serviceprovider/5453-a87f77787d-khj899" Text="Manage hotel" />
</Items>
</DxMenuItem-->
@* <DxMenuItem NavigateUrl="user/messages" Text="Messages" IconCssClass="fa-solid fa-envelope" /> *@
@{
@ -153,6 +156,7 @@
private bool expandHotelAdminNav = false;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private bool myUser = false;
private bool userHasCompany;
private bool userHasHotels;
private bool IsDriver;
@ -237,4 +241,56 @@
await SessionService.ClearAll();
NavigationManager.NavigateTo("/");
}
protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);
if (firstRender)
componentUpdateService.GetOrAddComponent<AdminNavMenu>().RefreshRequested += RefreshMe;
}
private void RefreshMe()
{
_logger.Debug($"Navbar refresh called! {DateTime.Now} ");
//OnInitialized();
InitUser();
StateHasChanged();
}
private void InitUser()
{
if (SessionService.User != null)
{
myUser = true;
userId = SessionService.User.UserId;
userEmail = SessionService.User.Email;
if (SessionService.User.UserModelDto.ProfileDto.FullName != null)
{
userFullName = SessionService.User.UserModelDto.ProfileDto.FullName!;
}
}
else
{
_logger.Debug($"Navbar myUser false! {DateTime.Now} ");
myUser = false;
}
var properties = SessionService.User?.HasProperties;
if (properties == null) return;
userHasCompany = SessionService.HasCompany;
userHasHotels = properties.Count > 0;
IsSysAdmin = SessionService.IsSysAdmin;
IsDevAdmin = SessionService.IsDevAdmin;
IsDriver = SessionService.IsDriver;
driverPermissionId = SessionService.DriverPersmissionId;
foreach (var property in properties)
{
_logger.Detail($"First property: {property.Value} ");
}
}
}

View File

@ -19,7 +19,7 @@
<ItemGroup>
<PackageReference Include="Blazor.AnimateOnScroll" Version="1.1.0" />
<PackageReference Include="BlazorAnimation" Version="2.2.0" />
<PackageReference Include="DevExpress.Blazor" Version="24.1.3" />
<PackageReference Include="DevExpress.Blazor" Version="24.2.3" />
<PackageReference Include="MessagePack" Version="2.5.187" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
@ -94,6 +94,9 @@
<Content Update="Pages\User\SysAdmins\AddressDetailGridComponent.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="wwwroot\images\car.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>

View File

@ -6,6 +6,11 @@
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Content Remove="Pages\Utility\DynamicForm.razor" />
<Content Remove="Shared\Users\NavigationHelperComponent.razor" />
</ItemGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
@ -14,10 +19,10 @@
<ItemGroup>
<PackageReference Include="Blazor.AnimateOnScroll" Version="1.1.0" />
<PackageReference Include="BlazorAnimation" Version="2.2.0" />
<PackageReference Include="DevExpress.Blazor" Version="23.2.3" />
<PackageReference Include="MessagePack" Version="2.5.168" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.6" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.6" />
<PackageReference Include="DevExpress.Blazor" Version="24.1.3" />
<PackageReference Include="MessagePack" Version="2.5.187" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
</ItemGroup>
<ItemGroup>
@ -74,9 +79,39 @@
</ItemGroup>
<ItemGroup>
<Content Update="Pages\RoadmapPage.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="Pages\User\CardComponents\CompanyCardComponent.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="Pages\User\Drivers\DriverManageCars.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="Pages\User\Hotels\HotelEditTransfers.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="Pages\User\SysAdmins\AddressDetailGridComponent.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Pages\Utility\DynamicForm.razor" />
<_ContentIncludedByDefault Remove="Shared\Users\NavigationHelperComponent.razor" />
</ItemGroup>
<ItemGroup>
<None Include="Pages\Utility\DynamicForm.razor" />
<None Include="Shared\Users\NavigationHelperComponent.razor" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Pages\Utility\DynamicForm.razor" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Shared\Users\NavigationHelperComponent.razor" />
</ItemGroup>
</Project>

View File

@ -6,14 +6,12 @@
body {
max-width: 100%;
overflow-x: hidden;
/*background-color: #e7e6f7;
background: url('../images/bg.jpg');*/
background-attachment: fixed;
background-position: center;
background-size: cover;
height: 100vh;
color: #58457b;
--bs-border-radius: 20px;
}
.content {
padding-left: 0px;
padding-right: 0px;
@ -25,8 +23,8 @@ body {
}
.container-fluid {
padding-left:40px;
padding-right: 40px;
padding-left: 0px;
padding-right: 0px;
}
.btn {
@ -134,11 +132,12 @@ select {
}
.bg-gradient {
color: #fff !important;
background: linear-gradient(111deg,deepskyblue,darkviolet,#502caf) !important;
background-size: 180% 180% !important;
animation: gradient-animation 3s ease infinite !important;
background-image: linear-gradient(21deg, deepskyblue, #6f42c1, #af2c53) !important;
/* background-size: 180% 180% !important; */
animation: gradient-animation 5s ease infinite !important;
background-attachment: fixed;
background-blend-mode: color;
}
@keyframes gradient-animation {
@ -279,11 +278,8 @@ select {
box-shadow: none;
}
.dxbl-grid .dxbl-grid-empty-data {
padding: 5px;
border-top: 0;
border-bottom: 0;
.dxbl-text-edit .dxbl-text-edit-input {
border-bottom: 1px solid;
}
.dxbl-tabs.dxbl-tabs-top > .dxbl-tabs-tablist {
@ -581,6 +577,213 @@ select:focus-visible {
/*End Hero Carousel*/
/* -------- Landing page ------- */
.game-section {
/*padding: 5px 50px;*/
}
.game-section .owl-stage {
margin: 15px 0;
display: flex;
display: -webkit-flex;
}
.game-section .item {
margin: 0 15px 60px;
width: 320px;
height: 400px;
display: flex;
display: -webkit-flex;
align-items: flex-end;
-webkit-align-items: flex-end;
background: #343434 no-repeat center center / cover;
border-radius: 16px;
overflow: hidden;
position: relative;
transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
cursor: pointer;
box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.57 );
}
.game-section .item.active {
width: 500px;
box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.57 );
-webkit-box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.57 );
}
.game-section .item:after {
content: "";
display: block;
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
}
.game-section .item-desc {
padding: 0 24px 12px;
color: #fff;
position: relative;
z-index: 1;
overflow: hidden;
transform: translateY(calc(100% - 54px));
-webkit-transform: translateY(calc(100% - 54px));
transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
}
.game-section .item.active .item-desc {
transform: none;
-webkit-transform: none;
}
.game-section .item-desc p {
opacity: 0;
-webkit-transform: translateY(32px);
transform: translateY(32px);
transition: all 0.4s ease-in-out 0.2s;
-webkit-transition: all 0.4s ease-in-out 0.2s;
}
.game-section .item.active .item-desc p {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
.game-section .owl-theme.custom-carousel .owl-dots {
margin-top: -20px;
position: relative;
z-index: 5;
}
/******** Middle section CSS End *******/
/***** responsive css Start ******/
@media (min-width: 992px) and (max-width: 1199px) {
h2 {
margin-bottom: 32px;
}
h3 {
margin: 0 0 8px;
font-size: 24px;
line-height: 32px;
}
/* -------- Landing page ------- */
.game-section {
/*padding: 50px 5px;*/
}
.game-section .item {
margin: 0 12px 60px;
width: 260px;
height: 360px;
}
.game-section .item.active {
width: 400px;
}
.game-section .item-desc {
transform: translateY(calc(100% - 46px));
-webkit-transform: translateY(calc(100% - 46px));
}
}
@media (min-width: 768px) and (max-width: 991px) {
h2 {
margin-bottom: 32px;
}
h3 {
margin: 0 0 8px;
font-size: 24px;
line-height: 32px;
}
.line-title {
width: 330px;
}
/* -------- Landing page ------- */
.game-section {
/*padding: 50px 5px 40px;*/
}
.game-section .item {
margin: 0 12px 60px;
width: 240px;
height: 330px;
}
.game-section .item.active {
width: 360px;
}
.game-section .item-desc {
transform: translateY(calc(100% - 42px));
-webkit-transform: translateY(calc(100% - 42px));
}
}
@media (max-width: 767px) {
body {
font-size: 14px;
}
h2 {
margin-bottom: 20px;
}
h3 {
margin: 0 0 8px;
font-size: 19px;
line-height: 24px;
}
.line-title {
width: 250px;
}
/* -------- Landing page ------- */
.game-section {
padding: 30px 15px 20px;
}
.game-section .item {
margin: 0 10px 40px;
width: 200px;
height: 280px;
}
.game-section .item.active {
width: 270px;
box-shadow: 6px 10px 10px rgba(0, 0, 0, 0.25);
-webkit-box-shadow: 6px 10px 10px rgba(0, 0, 0, 0.25);
}
.game-section .item-desc {
padding: 0 14px 5px;
transform: translateY(calc(100% - 42px));
-webkit-transform: translateY(calc(100% - 42px));
}
}
/*Admin*/
.gradient-custom-2 {
@ -688,3 +891,5 @@ select:focus-visible {
}
/*Admin end*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -57,7 +57,9 @@ builder.Services.AddSingleton<ExchangeRateService>();
builder.Services.AddSingleton<SmartyStreetsService>();
builder.Services.AddSingleton<GooglePlacesService>();
builder.Services.AddSingleton<PageHistoryState>();
//builder.Services.AddSingleton<BrowserConsoleLogWriter>();
builder.Services.AddScoped<BlogService>();
builder.Services.AddScoped<TourService>();
//builder.Services.AddScoped<BrowserConsoleLogWriter>();
//WebSpecific end

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>D:\REPOS\AYCODE\Publish\ServerRelease</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<ProjectGuid>2091d897-ba49-4fc1-808f-036fa040376e</ProjectGuid>
<SelfContained>true</SelfContained>
</PropertyGroup>
</Project>

View File

@ -3,6 +3,7 @@ using TIAM.Entities.Emails;
//using TIAM.Entities.TransferDestinations;
using TIAMWebApp.Shared.Application.Interfaces;
using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels;
using EmailMessage = TIAM.Entities.Emails.EmailMessage;
namespace TIAMWebApp.Client.Services
{

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>http</ActiveDebugProfile>
<ActiveDebugProfile>https</ActiveDebugProfile>
<NameOfLastUsedPublishProfile>D:\REPOS\AYCODE\source\TourIAm\TIAMWebApp\Client\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>

View File

@ -0,0 +1,213 @@
using GoogleApi.Entities.Search.Video.Common;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Text.RegularExpressions;
using TIAMWebApp.Shared.Application.Models;
namespace TIAMWebApp.Server.Controllers
{
[ApiController]
[Route("api/blog")]
public class BlogAPIController : ControllerBase
{
private readonly IWebHostEnvironment _env;
private readonly string _dataPath;
private readonly string _coverPath;
public BlogAPIController(IWebHostEnvironment env)
{
_env = env;
_dataPath = Path.Combine(_env.WebRootPath, "data");
_coverPath = Path.Combine(_env.WebRootPath, "uploads", "covers");
Directory.CreateDirectory(_dataPath);
Directory.CreateDirectory(_coverPath);
}
// ✅ Get All Posts
[HttpGet]
public IActionResult GetAll()
{
var files = Directory.GetFiles(_dataPath, "*.json");
var posts = files.Select(file =>
{
var json = System.IO.File.ReadAllText(file);
return JsonSerializer.Deserialize<BlogPostMetadata>(json);
}).ToList();
return Ok(posts);
}
// ✅ Get Single Post
[HttpGet("{id}")]
public IActionResult GetById(string id)
{
var file = Path.Combine(_dataPath, $"{id}.json");
if (!System.IO.File.Exists(file))
return NotFound();
var json = System.IO.File.ReadAllText(file);
var post = JsonSerializer.Deserialize<BlogPostMetadata>(json);
return Ok(post);
}
// ✅ Create Post (with optional cover upload)
[HttpPost]
public async Task<IActionResult> Create([FromForm] BlogPostForm form)
{
var post = new BlogPostMetadata
{
Title = form.Title,
Lead = form.Lead,
DriveLink = form.DriveLink,
Tags = form.Tags.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList()
};
if (form.CoverImage != null)
{
string fileName = $"{post.Id}{Path.GetExtension(form.CoverImage.FileName)}";
string filePath = Path.Combine(_coverPath, fileName);
await using var fs = System.IO.File.Create(filePath);
await form.CoverImage.CopyToAsync(fs);
post.CoverImage = $"/uploads/covers/{fileName}";
}
string jsonPath = Path.Combine(_dataPath, $"{post.Id}.json");
await System.IO.File.WriteAllTextAsync(jsonPath, JsonSerializer.Serialize(post));
return Ok(post);
}
//// ✅ Update Post
//[HttpPut("{id}")]
//public async Task<IActionResult> Update(string id, [FromBody] BlogPostMetadata post)
//{
// string jsonPath = Path.Combine(_dataPath, $"{id}.json");
// if (!System.IO.File.Exists(jsonPath))
// return NotFound();
// post.Id = id; // Ensure correct ID
// await System.IO.File.WriteAllTextAsync(jsonPath, JsonSerializer.Serialize(post));
// return Ok(post);
//}
[HttpPut("{id}")]
public async Task<IActionResult> Update(string id)
{
var form = await Request.ReadFormAsync();
// Parse metadata fields
var title = form["Title"].ToString();
var lead = form["Lead"].ToString();
var tags = form["Tags"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
var driveLink = form["DriveLink"].ToString();
string coverImagePath = null;
var file = form.Files.GetFile("CoverImage");
if (file != null)
{
var ext = Path.GetExtension(file.FileName);
var fileName = $"{id}{ext}";
var filePath = Path.Combine(_coverPath, fileName);
using var stream = System.IO.File.Create(filePath);
await file.CopyToAsync(stream);
// Save relative path
coverImagePath = $"/uploads/covers/{fileName}";
}
// Load existing metadata
string jsonPath = Path.Combine(_dataPath, $"{id}.json");
if (!System.IO.File.Exists(jsonPath))
return NotFound();
var existingJson = await System.IO.File.ReadAllTextAsync(jsonPath);
var existing = JsonSerializer.Deserialize<BlogPostMetadata>(existingJson);
// Update values
existing.Title = title;
existing.Lead = lead;
existing.Tags = tags;
existing.DriveLink = driveLink;
existing.CoverImage = coverImagePath;
if (!string.IsNullOrWhiteSpace(coverImagePath))
existing.CoverImage = coverImagePath;
await System.IO.File.WriteAllTextAsync(jsonPath, JsonSerializer.Serialize(existing));
return Ok(existing);
}
// ✅ Delete Post
[HttpDelete("{id}")]
public IActionResult Delete(string id)
{
string jsonPath = Path.Combine(_dataPath, $"{id}.json");
if (!System.IO.File.Exists(jsonPath))
return NotFound();
var post = JsonSerializer.Deserialize<BlogPostMetadata>(System.IO.File.ReadAllText(jsonPath));
if (!string.IsNullOrEmpty(post?.CoverImage))
{
var coverPath = Path.Combine(_env.WebRootPath, post.CoverImage.TrimStart('/').Replace("/", Path.DirectorySeparatorChar.ToString()));
if (System.IO.File.Exists(coverPath))
System.IO.File.Delete(coverPath);
}
System.IO.File.Delete(jsonPath);
return NoContent();
}
[HttpGet("postcontent/{postId}")]
public async Task<IActionResult> GetPostContent(string postId)
{
// Load metadata (adjust this to your actual metadata loading logic)
var metadataPath = Path.Combine(_dataPath, $"{postId}.json");
if (!System.IO.File.Exists(metadataPath))
{
return NotFound("Post metadata not found.");
}
var metadataJson = await System.IO.File.ReadAllTextAsync(metadataPath);
var metadata = System.Text.Json.JsonSerializer.Deserialize<BlogPostMetadata>(metadataJson);
if (metadata == null || string.IsNullOrEmpty(metadata.DriveLink))
{
return BadRequest("Invalid post metadata.");
}
// Extract file ID from Google Drive link
string? fileId = ExtractGoogleDriveFileId(metadata.DriveLink);
if (string.IsNullOrEmpty(fileId))
{
return BadRequest("Invalid Drive link.");
}
// Download blog content from Drive
string downloadUrl = $"https://drive.google.com/uc?export=download&id={fileId}";
using var httpClient = new HttpClient();
var content = await httpClient.GetStringAsync(downloadUrl);
return Content(content, "text/html");
}
private string? ExtractGoogleDriveFileId(string driveLink)
{
var match = Regex.Match(driveLink, @"\/d\/([^\/]+)");
return match.Success ? match.Groups[1].Value : null;
}
public class BlogPostForm
{
public string Title { get; set; }
public string Lead { get; set; }
public string DriveLink { get; set; }
public string Tags { get; set; }
public IFormFile CoverImage { get; set; }
}
}
}

View File

@ -0,0 +1,174 @@
using GoogleApi.Entities.Maps.Routes.Common;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using TIAM.Entities.Transfers;
using TIAMWebApp.Shared.Application.Models;
namespace TIAMWebApp.Server.Controllers;
[ApiController]
[Route("api/tours")]
public class TourAPIController : ControllerBase
{
private readonly IWebHostEnvironment _env;
private readonly string _toursPath;
private readonly string _coverPath;
public TourAPIController(IWebHostEnvironment env)
{
_env = env;
_toursPath = Path.Combine(_env.WebRootPath, "data", "tours");
_coverPath = Path.Combine(_env.WebRootPath, "uploads", "tourcovers");
Directory.CreateDirectory(_toursPath);
Directory.CreateDirectory(_coverPath);
}
[HttpGet]
public ActionResult<IEnumerable<TourInfo>> GetAll()
{
var files = Directory.GetFiles(_toursPath, "*.json");
var tours = files.Select(file =>
{
var json = System.IO.File.ReadAllText(file);
return JsonSerializer.Deserialize<TourInfo>(json);
}).Where(t => t != null).ToList();
return Ok(tours);
}
[HttpGet("{transferDestinationId}")]
public ActionResult<TourInfo> Get(Guid transferDestinationId)
{
var path = GetPath(transferDestinationId);
if (!System.IO.File.Exists(path))
return NotFound();
var json = System.IO.File.ReadAllText(path);
var tour = JsonSerializer.Deserialize<TourInfo>(json);
return Ok(tour);
}
[HttpPost]
public async Task<IActionResult> Create([FromForm] TourForm form)
{
var tour = new TourInfo
{
TransferDestinationId = Guid.Parse(form.TransferDestinationId),
Title = form.Title,
FancyDescription = form.Description,
Created = DateTime.UtcNow,
Modified = DateTime.UtcNow
};
// Save cover image if exists
if (form.CoverImage != null)
{
string fileName = $"{tour.TransferDestinationId}{Path.GetExtension(form.CoverImage.FileName)}";
string savePath = Path.Combine(_coverPath, fileName);
Directory.CreateDirectory(_coverPath); // Ensure folder exists
await using var fs = System.IO.File.Create(savePath);
await form.CoverImage.CopyToAsync(fs);
tour.CoverImageUrl = $"/uploads/tourcovers/{fileName}";
}
// Save metadata as JSON
var jsonPath = GetPath(tour.TransferDestinationId);
var json = JsonSerializer.Serialize(tour, new JsonSerializerOptions { WriteIndented = true });
await System.IO.File.WriteAllTextAsync(jsonPath, json);
return Ok(tour);
}
[HttpPut("{transferDestinationId}")]
public async Task<IActionResult> Update(Guid transferDestinationId, [FromBody] TourInfo updated)
{
var path = GetPath(transferDestinationId);
if (!System.IO.File.Exists(path))
return NotFound();
updated.TransferDestinationId = transferDestinationId;
updated.Modified = DateTime.UtcNow;
var json = JsonSerializer.Serialize(updated, new JsonSerializerOptions { WriteIndented = true });
await System.IO.File.WriteAllTextAsync(path, json);
return Ok(updated);
}
[HttpDelete("{transferDestinationId}")]
public IActionResult Delete(Guid transferDestinationId)
{
var path = GetPath(transferDestinationId);
if (!System.IO.File.Exists(path))
return NotFound();
System.IO.File.Delete(path);
return NoContent();
}
//[HttpPost("{id}/image")]
//public async Task<IActionResult> UploadTourImage(Guid id, IFormFile file)
//{
// if (file == null || file.Length == 0)
// return BadRequest("No file uploaded.");
// var ext = Path.GetExtension(file.FileName);
// var fileName = $"{id}{ext}";
// var filePath = Path.Combine(_coverPath, fileName);
// Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
// using var stream = System.IO.File.Create(filePath);
// await file.CopyToAsync(stream);
// // Optionally: update metadata to store file path (e.g., in a JSON file or DB)
// return Ok();
//}
[HttpPost("{id}/image")]
public async Task<IActionResult> UploadTourImage(Guid id, IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file uploaded.");
var ext = Path.GetExtension(file.FileName);
var fileName = $"{id}{ext}";
//var folderPath = Path.Combine("wwwroot", "uploads", "tours", id.ToString());
//Directory.CreateDirectory(folderPath);
var filePath = Path.Combine(_coverPath, fileName);
using var stream = System.IO.File.Create(filePath);
await file.CopyToAsync(stream);
// ✅ Update TourInfo JSON
var jsonPath = GetPath(id); // Same as in your PUT method
if (!System.IO.File.Exists(jsonPath))
return NotFound("TourInfo JSON not found.");
var json = await System.IO.File.ReadAllTextAsync(jsonPath);
var tour = JsonSerializer.Deserialize<TourInfo>(json);
// Relative path to serve the image (adjust if needed)
var relativeImagePath = Path.Combine("uploads", "tourcovers", fileName).Replace("\\", "/");
tour!.CoverImageUrl = "/" + relativeImagePath;
tour.Modified = DateTime.UtcNow;
var updatedJson = JsonSerializer.Serialize(tour, new JsonSerializerOptions { WriteIndented = true });
await System.IO.File.WriteAllTextAsync(jsonPath, updatedJson);
return Ok();
}
private string GetPath(Guid id) =>
Path.Combine(_toursPath, $"{id}.json");
}

View File

@ -90,11 +90,12 @@ namespace TIAMWebApp.Server.Controllers
}
//[Authorize]
//[HttpGet]
//[Route(APIUrls.GetTransferDriversByTransferIdRouteName)]
[NonAction]
//[NonAction]
[AllowAnonymous]
[HttpPost]
[Route(APIUrls.GetTransferDestinationByIdRouteName)]
[SignalR(SignalRTags.GetTransferDestinationById)]
public async Task<TransferDestination?> GetTransferDestinationById(Guid transferDestinationId)
public async Task<TransferDestination?> GetTransferDestinationById([FromBody] Guid transferDestinationId)
{
var transferDestination = await _adminDal.GetTransferDestinationByIdAsync(transferDestinationId);
return transferDestination;
@ -108,6 +109,15 @@ namespace TIAMWebApp.Server.Controllers
return null;// await _transferDestinationDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.Latitude == latitude && x.Longitude == longitude);
}
//[AllowAnonymous]
//[HttpGet]
//[Route(APIUrls.GetTransferDestinationById)]
//public async Task<TransferDestination?> GetTransferDestinationById(Guid )
//{
// var transferDestination = await _adminDal.GetTransferDestinationByIdAsync(transferDestinationId);
// return transferDestination;
//}
[AllowAnonymous]
[HttpGet]
[Route("GetTransferDestinationByAddress")]
@ -494,10 +504,10 @@ namespace TIAMWebApp.Server.Controllers
{
if (!transfer.ProductId.IsNullOrEmpty())
{
var product = await _adminDal.GetProductByIdAsync((Guid)transfer.ProductId);
//var product = await _adminDal.GetProductByIdAsync((Guid)transfer.ProductId);
transfer.Price = _transferBackendService.GetTransferPrice(transfer.ProductId.Value, from, to, transfer.PassengerCount);
if (transfer.Price.HasValue && transfer.Price > 0)
if (transfer.Price is > 0)
{
transfer.Revenue = _transferBackendService.GetCommission((Guid)transfer.ProductId, (double)transfer.Price, to);
}
@ -766,6 +776,9 @@ namespace TIAMWebApp.Server.Controllers
_logger.Debug($"GetTransferDrivers called; transferId: {transferId}");
var result = await _adminDal.GetTransferToDriversByTransferIdAsync(transferId);
//System.IO.File.WriteAllText($"h://TiamJsons//{transferId}.json", result.ToJson());
return result;
}

View File

@ -115,7 +115,13 @@ namespace TIAMWebApp.Server.Controllers
if (!loggedInModel.IsLoggedIn)
{
_logger.Warning(@"User not valid! errorCode: " + loggedInModel.LoginErrorCode);
return null;
//return null;
return new MainResponse
{
Content = loggedInModel.LoginErrorCode,
IsSuccess = false,
ErrorMessage = "Not valid login."
};
}
var response = new MainResponse
@ -550,7 +556,7 @@ namespace TIAMWebApp.Server.Controllers
//send email
_logger.Info($"Created transfer, send emailMessage!!!");
var message = new MessageSenderModel<EmailMessage>();
var message = new MessageSenderModel<TIAM.Entities.Emails.EmailMessage>();
message.Message = new EmailMessage();
message.Message.EmailAddress = email;
message.Message.Id = Guid.NewGuid();

View File

@ -64,7 +64,8 @@ builder.Services.AddCors(options =>
{
options.AddPolicy(myAllowSpecificOrigins, policy =>
{
policy.AllowAnyOrigin();
policy.WithOrigins("http://touriam.com",
"http://www.touriam.com");
});
});

View File

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Common" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.22" />
<PackageReference Include="QRCoderNetCore" Version="1.0.0" />
<PackageReference Include="SendGrid" Version="9.29.3" />
@ -27,6 +27,7 @@
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.9.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.9.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.9.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
</ItemGroup>
<ItemGroup>

View File

@ -2,7 +2,9 @@
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile>
<NameOfLastUsedPublishProfile>C:\REPOS\AYCODE\source\TourIAm\TIAMWebApp\Server\Properties\PublishProfiles\ReleaseDeployProfile.pubxml</NameOfLastUsedPublishProfile>
<NameOfLastUsedPublishProfile>D:\REPOS\AYCODE\source\TourIAm\TIAMWebApp\Server\Properties\PublishProfiles\ReleaseDeployProfile.pubxml</NameOfLastUsedPublishProfile>
<Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>

View File

@ -1,7 +1,10 @@
{
"ConnectionStrings": {
"DeveloperDbConnection": "Data Source=185.51.190.197;Initial Catalog=TIAM_DEV;Trusted_Connection=false;Encrypt=false;TrustServerCertificate=True;Connect Timeout=200;User ID=Anata_Development_Team;Password=v6f_?xNfg9N1;MultipleActiveResultSets=true"
},
"ConnectionStrings": {
//"DeveloperDbConnection": "Data Source=185.51.190.197;Initial Catalog=TIAM_DEV;Trusted_Connection=false;Encrypt=false;TrustServerCertificate=True;Connect Timeout=200;User ID=Anata_Development_Team;Password=v6f_?xNfg9N1;MultipleActiveResultSets=true"
//"DeveloperDbConnection": "Data Source=194.164.235.47;Initial Catalog=TIAM_DEV;Trusted_Connection=false;Encrypt=false;TrustServerCertificate=True;Connect Timeout=200;User ID=Anata_Development_Team;Password=v6f_?xNfg9N1;MultipleActiveResultSets=true"
"DeveloperDbConnection": "Data Source=195.26.231.218;Initial Catalog=TIAM_DEV;Trusted_Connection=false;Encrypt=false;TrustServerCertificate=True;Connect Timeout=200;User ID=sa;Password=v6f_?xNfg9N1;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
{
"Id": "00000000-0000-0000-0000-000000000000",
"TransferDestinationId": "171fcca4-ffd5-4380-9402-f27447af1e08",
"Title": "Downtown",
"FancyDescription": "fdshjklhsjfkslh dfjkhsjklfhd jkkslhfdsjkfh dskfh dsklhf dsjkl fdhjkl fdshjk fkjld hlkdskl dsjk fdjlfh dskh fdsjkfdshl khf dk hldsk hldskh dsjk hdslkf dhjkh dsfk fdslsk",
"CoverImageUrl": "/uploads/tourcovers/171fcca4-ffd5-4380-9402-f27447af1e08.png",
"Created": "2025-07-28T06:29:35.6626494Z",
"Modified": "2025-07-28T06:29:35.6626499Z"
}

View File

@ -0,0 +1,9 @@
{
"Id": "00000000-0000-0000-0000-000000000000",
"TransferDestinationId": "72a29052-0d99-49ec-a103-3b5ca86b5b4c",
"Title": "Rept\u00E9ri t\u00FAra",
"FancyDescription": "jhkl hjk hjfdsklh sjklfh sjkfh sjklfhdsjlfh djkf hdjklf hjk fldshjkf hdsjkf hdjk fhdsjkf hdsjklfhdjklf dhjkf hdsjklfdhjkldsfh jklsdfhjkfslhfjkslh fdsklh fjklhfdsjklhdsjkfdshjkfdhjksdlhjksdh skl",
"CoverImageUrl": "/uploads/tourcovers/72a29052-0d99-49ec-a103-3b5ca86b5b4c.jpeg",
"Created": "2025-07-27T18:05:27.5184619Z",
"Modified": "2025-07-27T18:05:27.5184622Z"
}

View File

@ -0,0 +1,9 @@
{
"Id": "00000000-0000-0000-0000-000000000000",
"TransferDestinationId": "ac30e313-6752-4358-b686-65a57be7a030",
"Title": "T\u00FAra 2",
"FancyDescription": "jkhk lhjdh fksldh fjk hsfjklh jdskhfsjk fhdsjk fhsjklfhsjlhf dsjkh fdsjklfh sjklhf sjdkhf sjklhfsjkfh dsjklhf dsjk hfdsjklhfdsklhfjdkslhfdsjklhf dsjklhf dsjkl hfdslh fdsjkh fsjkl hfdsjklfh sjkh fdskh fdkslfhjkshfdsl hfdskl",
"CoverImageUrl": "/uploads/tourcovers/ac30e313-6752-4358-b686-65a57be7a030.jpeg",
"Created": "2025-07-27T16:24:56.1635945Z",
"Modified": "2025-07-27T16:24:56.1635947Z"
}

View File

@ -0,0 +1,9 @@
{
"Id": "00000000-0000-0000-0000-000000000000",
"TransferDestinationId": "ae7c3d59-e9fb-4393-a89c-3124ed5eba04",
"Title": "Valami",
"FancyDescription": "jkhjdkhfjkdhfjsklhf jskh fsjdklfh sjkh fsjdk hfdsjkh fdsk hfdskl hdfsjkh fjdsklfh jdkl hfjkdslhfdjskh fdjsk hfsjklfh sdjh fdsjklfh sjk hfjklh fsjklhdls",
"CoverImageUrl": "/uploads/tourcovers/ae7c3d59-e9fb-4393-a89c-3124ed5eba04.jpeg",
"Created": "0001-01-01T00:00:00",
"Modified": "2025-07-28T06:26:09.0304045Z"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@ -1,4 +1,5 @@
using TIAM.Entities.Emails;
using EmailMessage = TIAM.Entities.Emails.EmailMessage;
namespace TIAMWebApp.Shared.Application.Interfaces
{

View File

@ -8,6 +8,7 @@ namespace TIAMWebApp.Shared.Application.Interfaces
Task<List<TransferDestination>> GetDestinationsAsync();
Task<TransferDestination?> GetTransferDestinationbyCoordinatesAsync(string destinationId);
Task<TransferDestination?> GetTransferDestinationbyAddressAsync(string destinationId);
Task<TransferDestination?> GetTransferDestinationbyIdAsync(Guid destinationId);
Task<TransferDestination?> CreateTransferDestination(TransferDestination model);
Task<TransferDestination?> UpdateTransferDestination(TransferDestination model);

View File

@ -96,6 +96,9 @@ namespace TIAMWebApp.Shared.Application.Models
public const string GetTransferDestinationByAddressRouteName = "GetTransferDestinationByAddress";
public const string GetTransferDestinationByAddress = TransferDataAPI + GetTransferDestinationByAddressRouteName;
public const string GetTransferDestinationByIdRouteName = "GetTransferDestinationById";
public const string GetTransferDestinationById = TransferDataAPI + GetTransferDestinationByIdRouteName;
public const string CreateTransferDestinationRouteName = "CreateTransferDestination";
public const string CreateTransferDestination = TransferDataAPI + CreateTransferDestinationRouteName;

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TIAMWebApp.Shared.Application.Models
{
public class BlogPostMetadata
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Title { get; set; }
public string Lead { get; set; }
public string DriveLink { get; set; }
public string CoverImage { get; set; } // Relative URL
public List<string> Tags { get; set; } = new();
}
}

View File

@ -8,10 +8,10 @@ namespace TIAMWebApp.Shared.Application.Models.ClientSide
//public static string BaseUrl = "https://touriam.mangoweb.hu";
//public static string ApiBaseUrl = "https://touriam.mangoweb.hu";
#if RELEASE
public static string BaseUrl = "https://test.touriam.com";
public static string ApiBaseUrl = "https://test.touriam.com";
//public static string BaseUrl = "https://touriam.com";
//public static string ApiBaseUrl = "https://touriam.com";
//public static string BaseUrl = "https://test.touriam.com";
//public static string ApiBaseUrl = "https://test.touriam.com";
public static string BaseUrl = "https://touriam.com";
public static string ApiBaseUrl = "https://touriam.com";
//public static string BaseUrl = "https://qa.touriam.com";
//public static string ApiBaseUrl = "https://qa.touriam.com";
#else

View File

@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TIAMWebApp.Shared.Application.Models
{
public class TourForm
{
public string TransferDestinationId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public IFormFile? CoverImage { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TIAMWebApp.Shared.Application.Models
{
public class TourInfo
{
public Guid Id { get; set; }
public Guid TransferDestinationId { get; set; }
public string Title { get; set; }
public string? FancyDescription { get; set; }
public string? CoverImageUrl { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
}

View File

@ -2,6 +2,7 @@
using AyCode.Core.Consts;
using AyCode.Core.Helpers;
using AyCode.Services.Loggers;
using AyCode.Services.SignalRs;
using Microsoft.Extensions.DependencyInjection;
using TIAM.Entities.Drivers;
using TIAM.Entities.Transfers;
@ -107,9 +108,7 @@ namespace TIAMWebApp.Shared.Application.Services
}
public async Task<List<TransferToDriver>> GetTransferDrivers(Guid transferId)
{
throw new NotImplementedException();
}
=> await GetByIdAsync<List<TransferToDriver>>(SignalRTags.GetTransferDriversByTransferId, transferId) ?? [];
public async Task<TransferToDriver?> AddTransferDriver(TransferToDriver transferToDriver)
{

View File

@ -0,0 +1,85 @@
using Microsoft.AspNetCore.Components.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using TIAMWebApp.Shared.Application.Models;
namespace TIAMWebApp.Shared.Application.Services
{
public class BlogService
{
private readonly HttpClient _http;
public BlogService(HttpClient http)
{
_http = http;
}
public async Task<List<BlogPostMetadata>> GetAllPostsAsync()
{
return await _http.GetFromJsonAsync<List<BlogPostMetadata>>("/api/blog") ?? new();
}
public async Task<BlogPostMetadata?> GetPostByIdAsync(string id)
{
return await _http.GetFromJsonAsync<BlogPostMetadata>($"/api/blog/{id}");
}
public async Task<BlogPostMetadata?> CreatePostAsync(BlogPostMetadata metadata, IBrowserFile? coverImage)
{
using var content = new MultipartFormDataContent();
content.Add(new StringContent(metadata.Title ?? ""), "Title");
content.Add(new StringContent(metadata.Lead ?? ""), "Lead");
content.Add(new StringContent(metadata.DriveLink ?? ""), "DriveLink");
content.Add(new StringContent(string.Join(",", metadata.Tags ?? new())), "Tags");
if (coverImage != null)
{
var fileContent = new StreamContent(coverImage.OpenReadStream(long.MaxValue));
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(coverImage.ContentType);
content.Add(fileContent, "CoverImage", coverImage.Name);
}
var response = await _http.PostAsync("/api/blog", content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<BlogPostMetadata>();
}
public async Task UpdatePostAsync(BlogPostMetadata metadata, IBrowserFile? newImageFile = null)
{
using var content = new MultipartFormDataContent();
content.Add(new StringContent(metadata.Title ?? ""), "Title");
content.Add(new StringContent(metadata.Lead ?? ""), "Lead");
content.Add(new StringContent(metadata.DriveLink ?? ""), "DriveLink");
content.Add(new StringContent(string.Join(",", metadata.Tags ?? new List<string>())), "Tags");
if (newImageFile != null)
{
var stream = newImageFile.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024); // 10 MB max
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(newImageFile.ContentType);
content.Add(fileContent, "CoverImage", newImageFile.Name);
}
var response = await _http.PutAsync($"/api/blog/{metadata.Id}", content);
response.EnsureSuccessStatusCode();
}
public async Task DeletePostAsync(string id)
{
var response = await _http.DeleteAsync($"/api/blog/{id}");
response.EnsureSuccessStatusCode();
}
}
}

Some files were not shown because too many files have changed in this diff Show More