add review submission flow (phase 3)
All checks were successful
deploy / deploy (push) Successful in 1m10s

- Add ReviewNotifier for verification emails
- Add review token generation and verification
- Add request_review_verification function
- Update reviews_section component with write-a-review form
- Create ReviewForm LiveView for submitting/editing reviews
- Add /reviews/new and /reviews/:id/edit routes
- Add review buttons to order detail page
- Update block_types to load real review data
- Tests for token and verification functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-04-01 11:12:25 +01:00
parent 8dc17a6f4d
commit 32eb0c6758
12 changed files with 835 additions and 34 deletions

View File

@@ -311,11 +311,11 @@ defmodule Berrypod.PagesTest do
test "loads review data when reviews_section block is present" do
blocks = [%{"type" => "reviews_section", "settings" => %{}}]
data = Pages.load_block_data(blocks, %{})
data = Pages.load_block_data(blocks, %{mode: :preview})
assert is_list(data.reviews)
assert data.average_rating == 5
assert data.total_count == 24
assert Decimal.equal?(data.average_rating, Decimal.new(5))
assert data.review_count == 2
end
test "loads featured products with configurable count" do

View File

@@ -382,4 +382,73 @@ defmodule Berrypod.ReviewsTest do
assert Reviews.get_review(review.id) == nil
end
end
# ── Review tokens ────────────────────────────────────────────────────
describe "generate_review_token/2 and verify_review_token/1" do
test "generates and verifies a valid token" do
product = product_fixture()
email = "buyer@example.com"
token = Reviews.generate_review_token(email, product.id)
assert is_binary(token)
{:ok, result} = Reviews.verify_review_token(token)
assert result.email == email
assert result.product_id == product.id
end
test "normalises email to lowercase" do
product = product_fixture()
token = Reviews.generate_review_token("BUYER@EXAMPLE.COM", product.id)
{:ok, result} = Reviews.verify_review_token(token)
assert result.email == "buyer@example.com"
end
test "rejects invalid tokens" do
assert {:error, :invalid} = Reviews.verify_review_token("invalid_token")
end
end
describe "request_review_verification/3" do
test "returns error when email has not purchased product" do
product = product_fixture()
result =
Reviews.request_review_verification("nobody@example.com", product.id, product.title)
assert {:error, :no_purchase} = result
end
test "returns error when user has already reviewed" do
product = product_fixture()
{:ok, _} =
Reviews.create_review(%{
product_id: product.id,
email: "buyer@example.com",
author_name: "Jane",
rating: 5
})
result = Reviews.request_review_verification("buyer@example.com", product.id, product.title)
assert {:error, :already_reviewed} = result
end
test "sends verification email when user has purchased" do
conn = provider_connection_fixture(%{provider_type: "printify"})
product = product_fixture(%{provider_connection: conn})
variant = product_variant_fixture(%{product: product})
order_fixture(%{
customer_email: "buyer@example.com",
payment_status: "paid",
variant_id: variant.id
})
result = Reviews.request_review_verification("buyer@example.com", product.id, product.title)
assert {:ok, :sent} = result
end
end
end