Files
wordpress-theme-aksrt/inc/helpers/aksrt-header-userbox.php
T
kate522 4653128a18 feat(checkin): open reference-parity details modal from signed buttons
- Rebuild checkin details modal HTML 1:1 with reference theme:
  colorful header c-blue, user card (points/level), daily reward
  card and 7-day continuous mini cards
- Signed entry buttons (header dropdown, user-card badge, user
  center) become clickable checkin-details-link modal triggers
  instead of disabled buttons
- Swap data-signin-btn to details link in place after successful
  signin (reference .initiate-checkin replacement behavior)
- Add aksrt-checkin-details-modal runtime shell (modal-mini 400px)
- Remove dead code: legacy lite modal, admin-ajax details handler,
  /signin/history route, signin calendar; rebuild public bundles
- Update contract tests to the new checkin modal contract
2026-09-19 14:49:58 +08:00

246 lines
9.6 KiB
PHP

<?php
/**
* Header user-box density helpers (legacy subset).
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
if (!function_exists('aksrt_get_user_checkin_details_link')) :
/**
* 已签到详情弹窗触发链接(参考主题 zib_get_user_checkin_details_link 1:1):
* 打开刷新式 mini 弹窗(高 240,移动端底部弹出,每次都重新拉取)。
*
* @param string $class 沿用入口按钮的类。
* @param string $text 链接内文(含图标)。
*/
function aksrt_get_user_checkin_details_link(string $class = '', string $text = ''): string {
$class = trim($class . ' checkin-details-link');
return '<a class="' . esc_attr($class) . '" href="javascript:;"'
. ' data-aksrt-modal="remote"'
. ' data-aksrt-modal-url="' . esc_url(rest_url('aksrt/v1/signin/details')) . '"'
. ' data-aksrt-modal-class="aksrt-checkin-details-modal modal-mini"'
. ' data-aksrt-modal-height="240"'
. ' data-aksrt-modal-mobile-bottom="true"'
. ' data-aksrt-modal-cache="false">'
. $text
. '</a>';
}
endif;
if (!function_exists('aksrt_header_user_checkin_btn')) :
/**
* Check-in CTA for header dropdown and compact card placements.
*
* @param int $user_id Current user ID.
* @param bool $compact Render a short card-friendly label.
* @param string|null $class Override the classes and render the reference-parity
* <a> badge (user-card 签到书签); null keeps the header
* dropdown <button> runtime.
*/
function aksrt_header_user_checkin_btn(int $user_id = 0, bool $compact = false, ?string $class = null): string {
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
if ($user_id <= 0 || !class_exists('\AKSRT\Credits\Signin')) {
return '';
}
$cfg = class_exists('\AKSRT\Settings\Settings')
? \AKSRT\Settings\Settings::get_signin_reward_settings()
: ['enabled' => false];
if (empty($cfg['enabled'])) {
return '';
}
$signed = \AKSRT\Credits\Signin::get_instance()->is_signed_today($user_id);
// 已签到:与参考主题一致,入口按钮变为签到详情弹窗触发链接(可点击)。
if ($signed) {
$icon = '<i class="fa fas fa-calendar-check ml3 mr6" aria-hidden="true"></i>';
if ($class !== null) {
// 用户卡片签到书签:保留书签类与 is-done 视觉,仅将行为切换为打开详情弹窗。
return aksrt_get_user_checkin_details_link(
$class . ' is-done',
$icon . '<span>' . esc_html__('已签到', 'aksrt') . '</span>'
);
}
return aksrt_get_user_checkin_details_link(
'but block c-yellow aksrt-header-checkin is-done',
'<i class="fa fas fa-calendar-check" aria-hidden="true"></i> ' . esc_html($compact ? __('已签到', 'aksrt') : __('今日已签到', 'aksrt'))
);
}
$classes = $class ?? ('but block c-yellow aksrt-header-checkin' . ($compact ? ' aksrt-header-checkin--compact' : ''));
// Card badge variant (explicit $class, e.g. the user-card 签到 badge):
// reference parity renders an <a> so the badge inherits the card font
// instead of the UA button stylesheet (font/UI 1:1 with the reference).
if ($class !== null) {
return '<a class="' . esc_attr($classes) . '" href="javascript:;" data-signin-btn'
. ' data-signin-idle-label="' . esc_attr__('签到', 'aksrt') . '"'
. ' data-signin-done-label="' . esc_attr__('已签到', 'aksrt') . '">'
. '<i class="fa fas fa-calendar-check ml3 mr6" aria-hidden="true"></i>'
. '<span data-signin-label>' . esc_html__('签到', 'aksrt') . '</span>'
. '</a>';
}
return '<button type="button" class="' . esc_attr($classes) . '" data-signin-btn data-signin-idle-label="' . esc_attr__('签到', 'aksrt') . '" data-signin-done-label="' . esc_attr__('已签到', 'aksrt') . '">'
. '<i class="fa fas fa-calendar-check" aria-hidden="true"></i>'
. '<span data-signin-label>' . esc_html($compact ? __('签到', 'aksrt') : __('签到领取今日奖励', 'aksrt')) . '</span>'
. '</button>';
}
endif;
if (!function_exists('aksrt_render_signin_captcha')) :
/**
* Render the single global captcha mount used by every sign-in button.
*/
function aksrt_render_signin_captcha(): void {
if (
!is_user_logged_in()
|| !class_exists('\AKSRT\Credits\Signin')
|| !class_exists('\AKSRT\Settings\Settings')
|| empty(\AKSRT\Settings\Settings::get_signin_reward_settings()['enabled'])
|| !function_exists('aksrt_is_captcha_enabled_for')
|| !function_exists('aksrt_render_captcha')
|| !aksrt_is_captcha_enabled_for('signin')
) {
return;
}
?>
<div class="aksrt-signin-captcha" data-signin-captcha>
<?php aksrt_render_captcha('signin'); ?>
</div>
<?php
}
endif;
add_action('wp_footer', 'aksrt_render_signin_captcha');
if (!function_exists('aksrt_header_user_wallet_mini')) :
/**
* Mini wallet strip: credits + cash balance.
*/
function aksrt_header_user_wallet_mini(int $user_id = 0): string {
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
if ($user_id <= 0) {
return '';
}
$credits = aksrt_user_points($user_id);
$currency = class_exists('\AKSRT\Settings\Settings')
? \AKSRT\Settings\Settings::get_currency_name()
: __('积分', 'aksrt');
$wallet = aksrt_user_balance_decimal($user_id);
$center = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('credits') : '#';
$html = '<a class="aksrt-header-wallet flex ac jsb" href="' . esc_url($center) . '">';
$html .= '<span class="aksrt-header-wallet__item"><i class="fa fas fa-database" aria-hidden="true"></i> '
. esc_html($currency) . ' <b data-aksrt-points-value data-credits-value>' . esc_html(number_format_i18n($credits)) . '</b></span>';
$html .= '<span class="aksrt-header-wallet__item"><i class="fa fas fa-money-bill" aria-hidden="true"></i> '
. esc_html__('余额', 'aksrt') . ' <b data-aksrt-wallet-value>' . esc_html(number_format_i18n($wallet, 2)) . '</b></span>';
$html .= '</a>';
return $html;
}
endif;
if (!function_exists('aksrt_header_user_badges_row')) :
/**
* Identity / medal chips under profile.
*/
function aksrt_header_user_badges_row(int $user_id = 0): string {
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
if ($user_id <= 0 || !function_exists('aksrt_render_user_identity_chips')) {
return '';
}
// Certification is displayed beside the name and level icon in the profile row.
return '';
}
endif;
if (!function_exists('aksrt_header_payvip_bar')) :
/**
* VIP status / open CTA bar (legacy parity).
*/
function aksrt_header_payvip_bar(int $user_id = 0): string {
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
if ($user_id <= 0) {
return '';
}
$vip = class_exists('\AKSRT\Settings\Settings')
? \AKSRT\Settings\Settings::get_payment_vip_settings()
: ['enabled' => false, 'levels' => []];
if (empty($vip['enabled'])) {
return '';
}
$settings = class_exists('\AKSRT\Settings\Settings')
? \AKSRT\Settings\Settings::get_all()
: [];
$level = function_exists('aksrt_get_user_vip_level') ? (int) aksrt_get_user_vip_level($user_id) : 0;
if ($level > 0) {
$levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : [];
$name = (string) ($levels[$level]['name'] ?? ($level === 2 ? __('二级会员', 'aksrt') : __('一级会员', 'aksrt')));
$exp_label = '';
if (function_exists('aksrt_get_vip_info')) {
$info = aksrt_get_vip_info($user_id);
$expires = max(0, (int) ($info['expires'] ?? 0));
$exp_label = $expires > 0
? sprintf(__('到期时间:%s', 'aksrt'), wp_date('Y年m月d日', $expires))
: (string) ($info['expires_label'] ?? '');
}
$html = '<div class="mt10 em09 aksrt-header-payvip is-vip">';
$html .= '<span class="radius4 payvip-icon btn-block text-center vipbg-v2 level-' . (int) $level . ' aksrt-header-payvip__active">';
$html .= '<span class="aksrt-header-payvip__level">';
$html .= '<i class="fa fas fa-gem" aria-hidden="true"></i>';
$html .= '<span>' . esc_html($name) . '</span>';
$html .= '</span>';
if ($exp_label !== '') {
$html .= '<span class="aksrt-header-payvip__exp">' . esc_html($exp_label) . '</span>';
}
$html .= '</span></div>';
return $html;
}
if (empty($vip['nav_user_pay_vip'])) {
return '';
}
// Match check-in CTA geometry (full width, 6px radius) — not top-nav navbar-cta chips.
return '<div class="mt10 em09 aksrt-header-payvip">'
. '<a class="pay-vip but block payvip-icon aksrt-header-payvip__cta" href="javascript:;" vip-level="1">'
. '<i class="fa fas fa-gem" aria-hidden="true"></i>'
. '<span>' . esc_html__('开通会员 尊享会员权益', 'aksrt') . '</span>'
. '</a></div>';
}
endif;
if (!function_exists('aksrt_render_signout_modal')) :
/**
* Confirm logout modal markup (once per page).
*/
function aksrt_render_signout_modal(): void {
static $done = false;
if ($done || !is_user_logged_in()) {
return;
}
$done = true;
$logout = wp_logout_url(home_url('/'));
?>
<div class="modal fade" id="modal_signout" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-mini" role="document">
<div class="modal-content">
<div class="modal-body text-center" style="padding:24px;">
<div class="em2x mb10"><i class="fa fas fa-sign-out-alt" aria-hidden="true"></i></div>
<div class="mb15"><?php esc_html_e('确认退出当前账号?', 'aksrt'); ?></div>
<div class="but-average flex jc" style="gap:10px;">
<button type="button" class="but" data-dismiss="modal"><?php esc_html_e('取消', 'aksrt'); ?></button>
<a class="but c-red" href="<?php echo esc_url($logout); ?>"><?php esc_html_e('确认退出', 'aksrt'); ?></a>
</div>
</div>
</div>
</div>
</div>
<?php
}
endif;