225 lines
7.9 KiB
C#
225 lines
7.9 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using PlotLine.Models;
|
|
using PlotLine.Services;
|
|
using PlotLine.ViewModels;
|
|
|
|
namespace PlotLine.Controllers;
|
|
|
|
[Authorize]
|
|
[Route("onboarding")]
|
|
public sealed class OnboardingController(IOnboardingService onboarding) : Controller
|
|
{
|
|
[HttpGet("")]
|
|
public async Task<IActionResult> Index()
|
|
{
|
|
var model = await onboarding.GetWizardAsync();
|
|
return View(model);
|
|
}
|
|
|
|
[HttpGet("scan-review")]
|
|
public async Task<IActionResult> ScanReview(Guid? previewId)
|
|
{
|
|
var model = await onboarding.GetScanReviewAsync(previewId);
|
|
return model is null ? NotFound() : View(model);
|
|
}
|
|
|
|
[HttpPost("scan-review")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> SaveScanReview(ManuscriptScanReviewForm form, string intent = "save")
|
|
{
|
|
var readyToImport = string.Equals(intent, "continue", StringComparison.OrdinalIgnoreCase);
|
|
try
|
|
{
|
|
var model = await onboarding.SaveScanReviewAsync(form, readyToImport);
|
|
if (model is null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
TempData["OnboardingReviewMessage"] = readyToImport
|
|
? "Review saved. Next: import into PlotDirector."
|
|
: "Review choices saved.";
|
|
return readyToImport
|
|
? RedirectToAction(nameof(Index))
|
|
: RedirectToAction(nameof(ScanReview), new { previewId = form.PreviewID });
|
|
}
|
|
catch (InvalidOperationException ex)
|
|
{
|
|
ModelState.AddModelError(string.Empty, ex.Message);
|
|
var model = await onboarding.GetScanReviewAsync(form.PreviewID);
|
|
if (model is null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return View("ScanReview", model);
|
|
}
|
|
}
|
|
|
|
[HttpPost("welcome")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Welcome()
|
|
{
|
|
await onboarding.MoveToNextStepAsync();
|
|
return RedirectToAction(nameof(Index));
|
|
}
|
|
|
|
[HttpPost("writing-journey")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> WritingJourney(WritingJourneyOnboardingForm form)
|
|
{
|
|
if (!ModelState.IsValid || string.IsNullOrWhiteSpace(form.WritingJourney))
|
|
{
|
|
var model = await onboarding.GetWizardAsync();
|
|
model.CurrentStep = OnboardingSteps.WritingJourney;
|
|
model.StepNumber = 2;
|
|
return View(nameof(Index), model);
|
|
}
|
|
|
|
await onboarding.SaveWritingJourneyAsync(form.WritingJourney);
|
|
return RedirectToAction(nameof(Index));
|
|
}
|
|
|
|
[HttpPost("writing-software")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> WritingSoftware(WritingSoftwareOnboardingForm form)
|
|
{
|
|
if (!ModelState.IsValid || string.IsNullOrWhiteSpace(form.WritingSoftware))
|
|
{
|
|
var model = await onboarding.GetWizardAsync();
|
|
model.CurrentStep = OnboardingSteps.WritingSoftware;
|
|
model.StepNumber = 3;
|
|
return View(nameof(Index), model);
|
|
}
|
|
|
|
await onboarding.SaveWritingSoftwareAsync(form.WritingSoftware);
|
|
return RedirectToAction(nameof(Index));
|
|
}
|
|
|
|
[HttpPost("project")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Project(ProjectOnboardingForm form)
|
|
{
|
|
if (string.Equals(form.Mode, OnboardingSelectionModes.Create, StringComparison.Ordinal)
|
|
&& string.IsNullOrWhiteSpace(form.ProjectName))
|
|
{
|
|
ModelState.AddModelError(nameof(form.ProjectName), "Enter a project name.");
|
|
}
|
|
|
|
if (string.Equals(form.Mode, OnboardingSelectionModes.Select, StringComparison.Ordinal)
|
|
&& !form.SelectedProjectID.HasValue)
|
|
{
|
|
ModelState.AddModelError(nameof(form.SelectedProjectID), "Choose one of your active projects.");
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var invalidModel = await onboarding.GetWizardAsync();
|
|
invalidModel.CurrentStep = OnboardingSteps.Project;
|
|
invalidModel.StepNumber = 4;
|
|
invalidModel.ProjectForm = form;
|
|
return View(nameof(Index), invalidModel);
|
|
}
|
|
|
|
try
|
|
{
|
|
await onboarding.SaveProjectAsync(form);
|
|
}
|
|
catch (InvalidOperationException ex)
|
|
{
|
|
ModelState.AddModelError(string.Equals(form.Mode, OnboardingSelectionModes.Select, StringComparison.Ordinal)
|
|
? nameof(form.SelectedProjectID)
|
|
: nameof(form.ProjectName), ex.Message);
|
|
var invalidModel = await onboarding.GetWizardAsync();
|
|
invalidModel.CurrentStep = OnboardingSteps.Project;
|
|
invalidModel.StepNumber = 4;
|
|
invalidModel.ProjectForm = form;
|
|
return View(nameof(Index), invalidModel);
|
|
}
|
|
|
|
return RedirectToAction(nameof(Index));
|
|
}
|
|
|
|
[HttpPost("book")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Book(BookOnboardingForm form)
|
|
{
|
|
if (string.Equals(form.Mode, OnboardingSelectionModes.Create, StringComparison.Ordinal)
|
|
&& string.IsNullOrWhiteSpace(form.BookTitle))
|
|
{
|
|
ModelState.AddModelError(nameof(form.BookTitle), "Enter a book title.");
|
|
}
|
|
|
|
if (string.Equals(form.Mode, OnboardingSelectionModes.Select, StringComparison.Ordinal)
|
|
&& !form.SelectedBookID.HasValue)
|
|
{
|
|
ModelState.AddModelError(nameof(form.SelectedBookID), "Choose a book from the selected project.");
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var invalidModel = await onboarding.GetWizardAsync();
|
|
invalidModel.CurrentStep = OnboardingSteps.Book;
|
|
invalidModel.StepNumber = 5;
|
|
invalidModel.BookForm = form;
|
|
return View(nameof(Index), invalidModel);
|
|
}
|
|
|
|
try
|
|
{
|
|
await onboarding.SaveBookAsync(form);
|
|
}
|
|
catch (SubscriptionLimitException ex)
|
|
{
|
|
ModelState.AddModelError(nameof(form.BookTitle), ex.Message);
|
|
var invalidModel = await onboarding.GetWizardAsync();
|
|
invalidModel.CurrentStep = OnboardingSteps.Book;
|
|
invalidModel.StepNumber = 5;
|
|
invalidModel.BookForm = form;
|
|
return View(nameof(Index), invalidModel);
|
|
}
|
|
catch (InvalidOperationException ex)
|
|
{
|
|
ModelState.AddModelError(string.Equals(form.Mode, OnboardingSelectionModes.Select, StringComparison.Ordinal)
|
|
? nameof(form.SelectedBookID)
|
|
: nameof(form.BookTitle), ex.Message);
|
|
var invalidModel = await onboarding.GetWizardAsync();
|
|
invalidModel.CurrentStep = OnboardingSteps.Book;
|
|
invalidModel.StepNumber = 5;
|
|
invalidModel.BookForm = form;
|
|
return View(nameof(Index), invalidModel);
|
|
}
|
|
|
|
return RedirectToAction(nameof(Index));
|
|
}
|
|
|
|
[HttpPost("finish")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Finish()
|
|
{
|
|
await onboarding.MarkCompletedAsync();
|
|
TempData["ArchiveMessage"] = "Setup saved. You can return to setup preferences from your account menu.";
|
|
return RedirectToAction("Index", "Projects");
|
|
}
|
|
|
|
[HttpPost("back")]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Back(string currentStep)
|
|
{
|
|
var targetStep = currentStep switch
|
|
{
|
|
OnboardingSteps.WritingJourney => OnboardingSteps.Welcome,
|
|
OnboardingSteps.WritingSoftware => OnboardingSteps.WritingJourney,
|
|
OnboardingSteps.Project => OnboardingSteps.WritingSoftware,
|
|
OnboardingSteps.Book => OnboardingSteps.Project,
|
|
OnboardingSteps.NextPathPreview => OnboardingSteps.Book,
|
|
_ => OnboardingSteps.Welcome
|
|
};
|
|
|
|
await onboarding.SetCurrentStepAsync(targetStep);
|
|
|
|
return RedirectToAction(nameof(Index));
|
|
}
|
|
}
|