diff --git a/FoodsharingSiegen.Contracts/Entity/Interaction.cs b/FoodsharingSiegen.Contracts/Entity/Interaction.cs index 50f0ac1..02fc2e8 100644 --- a/FoodsharingSiegen.Contracts/Entity/Interaction.cs +++ b/FoodsharingSiegen.Contracts/Entity/Interaction.cs @@ -1,78 +1,86 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Data; -using System.Data.Common; -using System.Linq; -using System.Linq.Expressions; using FoodsharingSiegen.Contracts.Enums; namespace FoodsharingSiegen.Contracts.Entity { - /// - /// The interaction class (a. beging, 21.05.2022) + /// The interaction class (a. beging, 21.05.2022) /// public class Interaction { #region Public Properties /// - /// Gets or sets the value of the alert (ab) + /// Gets or sets the value of the alert (ab) /// public bool Alert { get; set; } /// - /// Gets or sets the value of the created (ab) + /// Gets or sets the value of the created (ab) /// public DateTime Created { get; set; } /// - /// Gets or sets the value of the date (ab) + /// Gets or sets the value of the date (ab) /// public DateTime Date { get; set; } /// - /// Gets or sets the value of the id (ab) + /// Gets or sets the feedback associated with the interaction. /// - [Key] public Guid Id { get; set; } + public InteractionFeedback Feedback { get; set; } = InteractionFeedback.Neutral; /// - /// Gets or sets the value of the info (ab) + /// Gets or sets additional information related to feedback for the interaction. + /// + public string? FeedbackInfo { get; set; } + + /// + /// Gets or sets the value of the id (ab) + /// + [Key] + public Guid Id { get; set; } + + /// + /// Gets or sets additional information associated with the interaction. /// public string? Info1 { get; set; } /// - /// Gets or sets the value of the not needed (ab) + /// Gets or sets the additional information (Info2) associated with the interaction. + /// + public string? Info2 { get; set; } + + /// + /// Gets or sets the value of the not needed (ab) /// public bool NotNeeded { get; set; } /// - /// Gets or sets the value of the prospect (ab) + /// Gets or sets the value of the prospect (ab) /// public Prospect Prospect { get; set; } /// - /// Gets or sets the value of the prospect id (ab) + /// Gets or sets the value of the prospect id (ab) /// public Guid ProspectID { get; set; } /// - /// Gets or sets the value of the type (ab) + /// Gets or sets the value of the type (ab) /// public InteractionType Type { get; set; } /// - /// Gets or sets the value of the user (ab) + /// Gets or sets the value of the user (ab) /// public User User { get; set; } /// - /// Gets or sets the value of the user id (ab) + /// Gets or sets the value of the user id (ab) /// public Guid UserID { get; set; } #endregion } -} +} \ No newline at end of file diff --git a/FoodsharingSiegen.Contracts/Enums/InteractionFeedback.cs b/FoodsharingSiegen.Contracts/Enums/InteractionFeedback.cs new file mode 100644 index 0000000..34d67ab --- /dev/null +++ b/FoodsharingSiegen.Contracts/Enums/InteractionFeedback.cs @@ -0,0 +1,12 @@ +namespace FoodsharingSiegen.Contracts.Enums +{ + /// + /// Represents the types of feedback that can be associated with an interaction. + /// + public enum InteractionFeedback + { + Neutral = 10, + Positive = 20, + Negative = 30 + } +} \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Controls/InteractionRow.razor b/FoodsharingSiegen.Server/Controls/InteractionRow.razor index 9beaaf2..8f3d7f9 100644 --- a/FoodsharingSiegen.Server/Controls/InteractionRow.razor +++ b/FoodsharingSiegen.Server/Controls/InteractionRow.razor @@ -31,10 +31,16 @@ } - @if (!string.IsNullOrWhiteSpace(interaction.Info1)) - { - (@interaction.Info1) - } +
+ @FeedbackBuilder(interaction) +
+ +
+ @if (!string.IsNullOrWhiteSpace(interaction.FeedbackInfo)) + { + (@interaction.FeedbackInfo) + } +
} } diff --git a/FoodsharingSiegen.Server/Controls/InteractionRow.razor.cs b/FoodsharingSiegen.Server/Controls/InteractionRow.razor.cs index 46ab37d..b144d37 100644 --- a/FoodsharingSiegen.Server/Controls/InteractionRow.razor.cs +++ b/FoodsharingSiegen.Server/Controls/InteractionRow.razor.cs @@ -1,7 +1,9 @@ +using System.Text; using FoodsharingSiegen.Contracts.Entity; using FoodsharingSiegen.Contracts.Enums; using FoodsharingSiegen.Server.BaseClasses; using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Primitives; namespace FoodsharingSiegen.Server.Controls { @@ -91,5 +93,28 @@ namespace FoodsharingSiegen.Server.Controls private bool NotNeeded => Interactions.Any(x => x.NotNeeded); #endregion + + private MarkupString FeedbackBuilder(Interaction interaction) + { + var infoList = new List(); + if(!string.IsNullOrWhiteSpace(interaction.Info1)) infoList.Add(interaction.Info1); + if(!string.IsNullOrWhiteSpace(interaction.Info2)) infoList.Add(interaction.Info2); + var infos = string.Join(" / ", infoList); + if (string.IsNullOrWhiteSpace(infos)) return new(); + + var sb = new StringBuilder(); + sb.Append("("); + + if (interaction.Feedback == InteractionFeedback.Positive) + sb.Append(""); + + if (interaction.Feedback == InteractionFeedback.Negative) + sb.Append(""); + + sb.Append($"{infos}"); + sb.Append(")"); + + return new(sb.ToString()); + } } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor b/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor index 197ca7e..bacb92c 100644 --- a/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor +++ b/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor @@ -1,4 +1,5 @@ -@inherits FsBase +@using FoodsharingSiegen.Contracts.Enums +@inherits FsBase @if (ShowNotNeeded) { @@ -25,14 +26,54 @@ -@if (ShowInfo) +@if (!string.IsNullOrWhiteSpace(Info1Name)) { - @InfoName + @Info1Name } +@if (!string.IsNullOrWhiteSpace(Info2Name)) +{ + + @Info2Name + + +} + +@if (AllowFeedback) +{ +
+
+ + Feedback +
+ + + + + +
+
+ @if (Interaction.Feedback == InteractionFeedback.Negative) + { +
+ + Feedback Info + + +
+ } +
+} +
diff --git a/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor.cs b/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor.cs index 6f480a5..e5ce1ce 100644 --- a/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor.cs +++ b/FoodsharingSiegen.Server/Dialogs/InteractionDialog.razor.cs @@ -24,7 +24,13 @@ namespace FoodsharingSiegen.Server.Dialogs #region Parameters [Parameter] - public string? InfoName { get; set; } + public bool AllowFeedback { get; set; } + + [Parameter] + public string? Info1Name { get; set; } + + [Parameter] + public string? Info2Name { get; set; } [Parameter] public Interaction Interaction { get; set; } = new(); @@ -35,9 +41,6 @@ namespace FoodsharingSiegen.Server.Dialogs [Parameter] public bool ShowAlert { get; set; } - [Parameter] - public bool ShowInfo { get; set; } - [Parameter] public bool ShowNotNeeded { get; set; } @@ -55,21 +58,26 @@ namespace FoodsharingSiegen.Server.Dialogs /// public static async Task ShowAsync(IModalService modalService, InteractionDialogParameter parameter) { - var showInfo = parameter.Type switch + var allowFeedback = parameter.Type switch { InteractionType.EinAb => true, - InteractionType.Complete => true, - InteractionType.IdCheck => true, - InteractionType.PrintPass => true, - InteractionType.ReleasedForVerification => true, _ => false }; - var infoName = parameter.Type switch + var info1Name = parameter.Type switch { InteractionType.EinAb => "Welcher Betrieb?", + InteractionType.Complete => "Kommentar", + InteractionType.IdCheck => "Kommentar", + InteractionType.PrintPass => "Kommentar", InteractionType.ReleasedForVerification => "Hinweis", - _ => "Kommentar" + _ => null + }; + + var info2Name = parameter.Type switch + { + InteractionType.EinAb => "Mit wem?", + _ => null }; var showAlert = parameter.Type switch @@ -95,8 +103,9 @@ namespace FoodsharingSiegen.Server.Dialogs await modalService.Show(parameter.HeaderText, p => { p.Add(nameof(Interaction), interaction); - p.Add(nameof(ShowInfo), showInfo); - p.Add(nameof(InfoName), infoName); + p.Add(nameof(AllowFeedback), allowFeedback); + p.Add(nameof(Info1Name), info1Name); + p.Add(nameof(Info2Name), info2Name); p.Add(nameof(ShowAlert), showAlert); p.Add(nameof(ShowNotNeeded), showNotNeeded); p.Add(nameof(OnSuccess), parameter.OnSuccess); @@ -124,5 +133,22 @@ namespace FoodsharingSiegen.Server.Dialogs } #endregion + + #region Private Method SetFeedbackAsync + + /// + /// Sets the feedback type for the interaction and updates the feedback property. + /// + /// The feedback type to be set for the interaction. + /// + /// A task representing the asynchronous operation. + /// + private async Task SetFeedbackAsync(InteractionFeedback feedback) + { + Interaction.Feedback = feedback; + await Task.CompletedTask; + } + + #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Migrations/20250401084453_Interaction-Feedback.Designer.cs b/FoodsharingSiegen.Server/Migrations/20250401084453_Interaction-Feedback.Designer.cs new file mode 100644 index 0000000..4deeae4 --- /dev/null +++ b/FoodsharingSiegen.Server/Migrations/20250401084453_Interaction-Feedback.Designer.cs @@ -0,0 +1,217 @@ +// +using System; +using FoodsharingSiegen.Server.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace FoodsharingSiegen.Server.Migrations +{ + [DbContext(typeof(FsContext))] + [Migration("20250401084453_Interaction-Feedback")] + partial class InteractionFeedback + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Data1") + .HasColumnType("TEXT"); + + b.Property("Data2") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserID") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserID"); + + b.ToTable("Audits"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Alert") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("Feedback") + .HasColumnType("INTEGER"); + + b.Property("FeedbackInfo") + .HasColumnType("TEXT"); + + b.Property("Info1") + .HasColumnType("TEXT"); + + b.Property("Info2") + .HasColumnType("TEXT"); + + b.Property("NotNeeded") + .HasColumnType("INTEGER"); + + b.Property("ProspectID") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserID") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProspectID"); + + b.HasIndex("UserID"); + + b.ToTable("Interactions"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Prospect", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FsId") + .HasColumnType("INTEGER"); + + b.Property("Memo") + .HasColumnType("TEXT"); + + b.Property("Modified") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RecordState") + .HasColumnType("INTEGER"); + + b.Property("Warning") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Prospects"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("EncryptedPassword") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ForceLogout") + .HasColumnType("INTEGER"); + + b.Property("Groups") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mail") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Memo") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Network") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Verified") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b => + { + b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User") + .WithMany() + .HasForeignKey("UserID"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b => + { + b.HasOne("FoodsharingSiegen.Contracts.Entity.Prospect", "Prospect") + .WithMany("Interactions") + .HasForeignKey("ProspectID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User") + .WithMany("Interactions") + .HasForeignKey("UserID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Prospect"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Prospect", b => + { + b.Navigation("Interactions"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.User", b => + { + b.Navigation("Interactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/FoodsharingSiegen.Server/Migrations/20250401084453_Interaction-Feedback.cs b/FoodsharingSiegen.Server/Migrations/20250401084453_Interaction-Feedback.cs new file mode 100644 index 0000000..9f684d1 --- /dev/null +++ b/FoodsharingSiegen.Server/Migrations/20250401084453_Interaction-Feedback.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FoodsharingSiegen.Server.Migrations +{ + /// + public partial class InteractionFeedback : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Feedback", + table: "Interactions", + type: "INTEGER", + nullable: false, + defaultValue: 10); + + migrationBuilder.AddColumn( + name: "FeedbackInfo", + table: "Interactions", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "Info2", + table: "Interactions", + type: "TEXT", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Feedback", + table: "Interactions"); + + migrationBuilder.DropColumn( + name: "FeedbackInfo", + table: "Interactions"); + + migrationBuilder.DropColumn( + name: "Info2", + table: "Interactions"); + } + } +} diff --git a/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs b/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs index bfeddb8..ce71748 100644 --- a/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs +++ b/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs @@ -60,9 +60,18 @@ namespace FoodsharingSiegen.Server.Migrations b.Property("Date") .HasColumnType("TEXT"); + b.Property("Feedback") + .HasColumnType("INTEGER"); + + b.Property("FeedbackInfo") + .HasColumnType("TEXT"); + b.Property("Info1") .HasColumnType("TEXT"); + b.Property("Info2") + .HasColumnType("TEXT"); + b.Property("NotNeeded") .HasColumnType("INTEGER");