import dataclasses import urllib.parse from dataclasses import dataclass from typing import Annotated, Any, TypedDict from fansifter_common.exceptions import Error from pydantic import BaseModel, BeforeValidator, Json, TypeAdapter from email_campaigns.api.schemas import CustomFont @dataclass(kw_only=True) class EmailPreview: id: str name: str subject: str | None preview_text: str | None sender_name: str | None html: str | None css: str | None custom_fonts: list[CustomFont] | None = dataclasses.field(default=None) favorite_fonts: list[CustomFont] | None = dataclasses.field(default=None) @dataclass(kw_only=True) class EmailContentErrorSummary: sender_name: Error | None = None subject: Error | None = None email_domain_id: Error | None = None email_username: Error | None = None html_content: Error | None = None class EmailAnalytics(BaseModel): campaign_id: str email_id: str email_type: str sends: int delivered: int opens: int clicks: int unique_opens: int unique_clicks: int bounces: int spam_complaints: int unsubscribes: int open_rate: float delivered_rate: float click_through_rate: float click_to_open_rate: float bounce_rate: float spam_complaints_rate: float unsubscribe_rate: float unique_clicks_dropoff: float | None unique_opens_dropoff: float | None bounce_rate_change: float | None spam_complaints_rate_change: float | None unsubscribe_rate_change: float | None open_rate_change: float | None delivered_rate_change: float | None unique_clicks_change: float | None click_through_rate_change: float | None click_to_open_rate_change: float | None EmailAnalyticsList = TypeAdapter(list[EmailAnalytics]) class EmailReportingAnalytics(TypedDict): sends: int delivered: int opens: int clicks: int bounces: int spam_complaints: int unsubscribes: int open_rate: float delivered_rate: float click_through_rate: float click_to_open_rate: float bounce_rate: float spam_complaints_rate: float unsubscribe_rate: float EmailReportingAnalyticsAdapter = TypeAdapter(EmailReportingAnalytics) class EmailLinkAnalytics(TypedDict): url: str total_clicks: int unique_clicks: int percentage_of_total_clicks: float class EmailReportingLinkAnalytics(TypedDict): url: str total_clicks: int percentage_of_total_clicks: float EmailReportingLinkAnalyticsList = TypeAdapter(list[EmailReportingLinkAnalytics]) EmailLinkAnalyticsList = TypeAdapter(list[EmailLinkAnalytics]) class EmailSalesAnalytics(TypedDict): orders_count: int items_sold: int net_sales_usd: float gross_sales_usd: float discounts_usd: float taxes_usd: float shipping_usd: float refunds_usd: float average_units_per_order: float average_order_amount: float first_time_buyer_rate: float EmailSalesAnalyticsAdapter = TypeAdapter(EmailSalesAnalytics) class EmailSalesProductAnalytics(TypedDict): product_title: str | None product_type: str | None items_sold: int net_sales_usd: float chart_eligible: bool EmailSalesProductAnalyticsList = TypeAdapter(list[EmailSalesProductAnalytics]) class EmailSalesLocationAnalytics(TypedDict): country_code: str | None items_sold: int net_sales_usd: float sales_rate: float EmailSalesLocationAnalyticsList = TypeAdapter(list[EmailSalesLocationAnalytics]) class EmailSalesShopAnalytics(TypedDict): shop_name: str items_sold: int net_sales_usd: float EmailSalesShopAnalyticsList = TypeAdapter(list[EmailSalesShopAnalytics]) UrlEncodedJson = Annotated[ Json[dict[str, Any]], BeforeValidator(urllib.parse.unquote), ]