You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
7.1 KiB

1 month ago
<?php
namespace App\Support;
use App\Models\Application;
use App\Models\AudienceRegistration;
use App\Models\AudienceSession;
use App\Models\Competition;
use App\Models\CompetitionTrack;
final class SignupDisplay
{
public const TRACK_OTHER_CODE = 'other';
public const TRACK_OTHER_FIELD = 'track_other';
public static function applicationLocale(Application $app): string
{
return PortalLocale::isValid((string) $app->signup_locale)
? (string) $app->signup_locale
: PortalLocale::ZH;
}
public static function localeTag(string $locale): string
{
return $locale === PortalLocale::EN ? '英文填报' : '中文填报';
}
/**
* @param list<mixed>|null $schemaJson
*/
public static function applicationFieldValue(Application $app, string $key): mixed
{
if ($key === 'track') {
return $app->track;
}
$columns = array_flip(SignupApplicationFieldRegistry::scalarColumnKeys());
if (isset($columns[$key])) {
return $app->{$key};
}
$answers = is_array($app->answers_json) ? $app->answers_json : [];
return $answers[$key] ?? null;
}
/**
* @param list<mixed>|null $schemaJson
*/
public static function applicationFieldLabel(
Competition $competition,
Application $app,
string $key,
?array $schemaJson = null,
): string {
$locale = self::applicationLocale($app);
$raw = self::applicationFieldValue($app, $key);
$value = is_scalar($raw) ? trim((string) $raw) : '';
if ($value === '') {
return '';
}
if ($key === 'degree') {
return SignupOptionCatalog::label(SignupOptionCatalog::degrees(), $value, $locale);
}
if ($key === 'location_country') {
return SignupOptionCatalog::label(SignupOptionCatalog::locationCountries(), $value, $locale);
}
if ($key === 'event_location') {
return SignupOptionCatalog::label(SignupOptionCatalog::eventLocations(), $value, $locale);
}
if ($key === 'track') {
if ($value === self::TRACK_OTHER_CODE) {
return $locale === PortalLocale::EN ? 'Other' : '其他';
}
$competition->loadMissing('tracks');
/** @var CompetitionTrack|null $track */
$track = $competition->tracks->firstWhere('track_code', $value);
if ($track === null) {
return $value;
}
return $locale === PortalLocale::EN && filled($track->title_en)
? (string) $track->title_en
: (string) $track->title;
}
$schema = $schemaJson ?? ($competition->formSchema?->schema_json ?? null);
$field = LocalizedSchema::fieldByKey(is_array($schema) ? $schema : null, $key);
if ($field !== null && ($field['type'] ?? '') === 'select') {
return LocalizedSchema::optionLabelForValue($field, $value, $locale);
}
return $value;
}
public static function trackTitleForApplication(Competition $competition, Application $app): string
{
$base = self::applicationFieldLabel($competition, $app, 'track');
if ($base === '') {
$base = trim((string) $app->track);
}
$note = trim((string) (self::applicationFieldValue($app, self::TRACK_OTHER_FIELD) ?? ''));
if ($note !== '' && (string) $app->track === self::TRACK_OTHER_CODE) {
return $base === '' ? $note : $base.'('.$note.')';
}
return $base;
}
4 weeks ago
public static function catalogLabel(string $kind, ?string $raw, string $locale = PortalLocale::ZH): string
{
$value = trim((string) $raw);
if ($value === '') {
return '';
}
$catalog = match ($kind) {
'degree' => SignupOptionCatalog::degrees(),
'location_country' => SignupOptionCatalog::locationCountries(),
'event_location' => SignupOptionCatalog::eventLocations(),
'purpose', 'audience_purpose' => SignupOptionCatalog::audiencePurposes(),
default => null,
};
if ($catalog === null) {
return $value;
}
return SignupOptionCatalog::label($catalog, $value, $locale);
}
public static function formatLocation(Application $app, string $locale = PortalLocale::ZH): string
1 month ago
{
$country = SignupOptionCatalog::normalize('location_country', (string) $app->location_country);
$countryLabel = $country !== null && $country !== ''
? SignupOptionCatalog::label(SignupOptionCatalog::locationCountries(), $country, $locale)
: '';
if ($country === 'cn') {
return implode(' / ', array_values(array_filter([
$countryLabel,
trim((string) $app->location_province),
trim((string) $app->location_city),
], fn ($v) => $v !== '')));
}
if ($country === 'overseas') {
return implode(' / ', array_values(array_filter([
$countryLabel,
trim((string) $app->oversea_country),
], fn ($v) => $v !== '')));
}
return $countryLabel;
}
public static function sessionName(AudienceSession $session, string $locale): string
{
return $locale === PortalLocale::EN && filled($session->name_en)
? (string) $session->name_en
: (string) $session->name;
}
public static function sessionDateText(AudienceSession $session, string $locale): string
{
return $locale === PortalLocale::EN && filled($session->event_date_text_en)
? (string) $session->event_date_text_en
: (string) $session->event_date_text;
}
public static function sessionAddress(AudienceSession $session, string $locale): string
{
return $locale === PortalLocale::EN && filled($session->address_en)
? (string) $session->address_en
: (string) $session->address;
}
public static function purposeLabel(string $code, string $locale): string
{
return SignupOptionCatalog::label(
SignupOptionCatalog::audiencePurposes(),
SignupOptionCatalog::normalize('purpose', $code) ?? $code,
$locale
);
}
public static function audienceLocale(int $userId, int $competitionId): string
{
$row = \App\Models\CompetitionPortalLocale::query()
->where('user_id', $userId)
->where('competition_id', $competitionId)
->where('portal', PortalLocale::PORTAL_AUDIENCE)
->first();
return $row && PortalLocale::isValid((string) $row->locale)
? (string) $row->locale
: PortalLocale::ZH;
}
public static function audienceFieldValue(AudienceRegistration $row, string $key): mixed
{
if (in_array($key, ['name', 'phone', 'company', 'job', 'purpose'], true)) {
return $row->{$key};
}
$answers = is_array($row->answers_json) ? $row->answers_json : [];
return $answers[$key] ?? null;
}
}