This commit is contained in:
2026-04-22 22:00:50 +02:00
parent 16be247ce1
commit e979fbe755
46 changed files with 5302 additions and 274 deletions

View File

@@ -8,14 +8,28 @@ class Carei_Admin_Panel {
const POST_TYPE = 'carei_reservation';
const META_PREFIX = '_carei_';
const PROTECTION_OPTION = 'carei_protection_packages';
const PROTECTION_OPTION = 'carei_protection_packages';
const EXTRAS_SEEN_OPTION = 'carei_extras_seen';
const EXTRAS_TRANSLATIONS_OPTION = 'carei_extras_translations';
private static $statuses = array(
'nowe' => array( 'label' => 'Nowe', 'color' => '#2F2482' ),
'przeczytane' => array( 'label' => 'Przeczytane', 'color' => '#f59e0b' ),
'zrealizowane' => array( 'label' => 'Zrealizowane', 'color' => '#22c55e' ),
'nowe' => array( 'color' => '#2F2482' ),
'przeczytane' => array( 'color' => '#f59e0b' ),
'zrealizowane' => array( 'color' => '#22c55e' ),
);
private static function get_status_label( $key ) {
switch ( $key ) {
case 'nowe':
return __( 'Nowe', 'carei-reservation' );
case 'przeczytane':
return __( 'Przeczytane', 'carei-reservation' );
case 'zrealizowane':
return __( 'Zrealizowane', 'carei-reservation' );
}
return $key;
}
public function __construct() {
add_action( 'init', array( $this, 'register_post_type' ) );
add_filter( 'manage_' . self::POST_TYPE . '_posts_columns', array( $this, 'admin_columns' ) );
@@ -28,6 +42,135 @@ class Carei_Admin_Panel {
add_action( 'admin_head', array( $this, 'admin_styles' ) );
add_action( 'admin_menu', array( $this, 'register_protection_packages_page' ) );
add_action( 'admin_post_carei_save_protection_packages', array( $this, 'handle_protection_packages_save' ) );
add_action( 'admin_menu', array( $this, 'register_extras_translations_page' ) );
add_action( 'admin_post_carei_save_extras_translations', array( $this, 'handle_extras_translations_save' ) );
}
// ─── Extras Translations (dynamic Softra pricelist item names) ────
public static function get_extras_seen() {
$seen = get_option( self::EXTRAS_SEEN_OPTION, array() );
if ( ! is_array( $seen ) ) return array();
$seen = array_values( array_unique( array_filter( array_map( 'strval', $seen ), 'strlen' ) ) );
sort( $seen, SORT_NATURAL | SORT_FLAG_CASE );
return $seen;
}
public static function get_extras_translations() {
$map = get_option( self::EXTRAS_TRANSLATIONS_OPTION, array() );
return is_array( $map ) ? $map : array();
}
public static function remember_extra_name( $pl_name ) {
$pl_name = trim( (string) $pl_name );
if ( $pl_name === '' ) return;
$seen = get_option( self::EXTRAS_SEEN_OPTION, array() );
if ( ! is_array( $seen ) ) $seen = array();
if ( ! in_array( $pl_name, $seen, true ) ) {
$seen[] = $pl_name;
update_option( self::EXTRAS_SEEN_OPTION, $seen, false );
}
}
public static function translate_extra_name( $pl_name, $locale = null ) {
if ( $locale === null ) {
$wp_locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
$locale = ( 0 === strpos( (string) $wp_locale, 'en' ) ) ? 'en' : 'pl';
}
if ( $locale !== 'en' ) return $pl_name;
$map = self::get_extras_translations();
if ( isset( $map[ $pl_name ] ) && $map[ $pl_name ] !== '' ) {
return $map[ $pl_name ];
}
return $pl_name;
}
public function register_extras_translations_page() {
add_submenu_page(
'edit.php?post_type=' . self::POST_TYPE,
__( 'Tłumaczenia extras', 'carei-reservation' ),
__( 'Tłumaczenia extras', 'carei-reservation' ),
'manage_options',
'carei-extras-translations',
array( $this, 'render_extras_translations_page' )
);
}
public function render_extras_translations_page() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Brak uprawnień.', 'carei-reservation' ) );
}
$seen = self::get_extras_seen();
$trans = self::get_extras_translations();
$saved = isset( $_GET['carei_saved'] ) && $_GET['carei_saved'] === '1';
?>
<div class="wrap">
<h1><?php esc_html_e( 'Tłumaczenia extras', 'carei-reservation' ); ?></h1>
<p><?php esc_html_e( 'Tłumaczenia nazw dodatkowych opcji (extras) zwracanych z API Softra. Puste pole = wersja polska jest używana także w wersji angielskiej (fallback).', 'carei-reservation' ); ?></p>
<?php if ( $saved ) : ?>
<div class="notice notice-success is-dismissible"><p><?php esc_html_e( 'Zapisano.', 'carei-reservation' ); ?></p></div>
<?php endif; ?>
<?php if ( empty( $seen ) ) : ?>
<div class="notice notice-info"><p><?php esc_html_e( 'Brak zebranych pozycji. Otwórz formularz rezerwacji i wybierz daty/oddział/klasę aby załadować pricelist — pozycje pojawią się tutaj automatycznie.', 'carei-reservation' ); ?></p></div>
<?php else : ?>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="carei-extras-form">
<input type="hidden" name="action" value="carei_save_extras_translations">
<?php wp_nonce_field( 'carei_extras_translations', 'carei_extras_nonce' ); ?>
<table class="form-table striped">
<thead>
<tr>
<th style="width: 40%;"><?php esc_html_e( 'Nazwa PL (z API Softra)', 'carei-reservation' ); ?></th>
<th><?php esc_html_e( 'Tłumaczenie EN', 'carei-reservation' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $seen as $pl_name ) :
$en = isset( $trans[ $pl_name ] ) ? (string) $trans[ $pl_name ] : '';
?>
<tr>
<td><strong><?php echo esc_html( $pl_name ); ?></strong></td>
<td>
<input type="text" name="translations[<?php echo esc_attr( $pl_name ); ?>]" value="<?php echo esc_attr( $en ); ?>" class="regular-text" placeholder="<?php echo esc_attr__( 'EN translation...', 'carei-reservation' ); ?>">
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php submit_button( __( 'Zapisz tłumaczenia', 'carei-reservation' ) ); ?>
</form>
<?php endif; ?>
</div>
<?php
}
public function handle_extras_translations_save() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Brak uprawnień.', 'carei-reservation' ) );
}
if ( ! isset( $_POST['carei_extras_nonce'] ) || ! wp_verify_nonce( $_POST['carei_extras_nonce'], 'carei_extras_translations' ) ) {
wp_die( esc_html__( 'Nieprawidłowy token.', 'carei-reservation' ) );
}
$input = isset( $_POST['translations'] ) && is_array( $_POST['translations'] ) ? $_POST['translations'] : array();
$clean = array();
foreach ( $input as $pl_name => $en_value ) {
$pl = trim( (string) wp_unslash( $pl_name ) );
$en = sanitize_text_field( wp_unslash( (string) $en_value ) );
if ( $pl === '' ) continue;
$clean[ $pl ] = $en;
}
update_option( self::EXTRAS_TRANSLATIONS_OPTION, $clean, false );
$redirect = add_query_arg(
array(
'post_type' => self::POST_TYPE,
'page' => 'carei-extras-translations',
'carei_saved' => '1',
),
admin_url( 'edit.php' )
);
wp_safe_redirect( $redirect );
exit;
}
// ─── Protection Packages (SOFT / PREMIUM) ────────────────────
@@ -35,16 +178,20 @@ class Carei_Admin_Panel {
public static function get_protection_packages_defaults() {
return array(
'soft' => array(
'name' => 'Ubezpieczenie SOFT',
'pricePerDay' => 0,
'active' => true,
'description' => '',
'name' => __( 'Ubezpieczenie SOFT', 'carei-reservation' ),
'name_en' => 'SOFT Protection',
'pricePerDay' => 0,
'active' => true,
'description' => '',
'description_en' => '',
),
'premium' => array(
'name' => 'Ubezpieczenie PREMIUM',
'pricePerDay' => 0,
'active' => true,
'description' => '',
'name' => __( 'Ubezpieczenie PREMIUM', 'carei-reservation' ),
'name_en' => 'PREMIUM Protection',
'pricePerDay' => 0,
'active' => true,
'description' => '',
'description_en' => '',
),
);
}
@@ -59,10 +206,12 @@ class Carei_Admin_Panel {
foreach ( $defaults as $key => $def ) {
$item = isset( $stored[ $key ] ) && is_array( $stored[ $key ] ) ? $stored[ $key ] : array();
$out[ $key ] = array(
'name' => isset( $item['name'] ) && $item['name'] !== '' ? (string) $item['name'] : $def['name'],
'pricePerDay' => isset( $item['pricePerDay'] ) ? (float) $item['pricePerDay'] : (float) $def['pricePerDay'],
'active' => isset( $item['active'] ) ? (bool) $item['active'] : (bool) $def['active'],
'description' => isset( $item['description'] ) ? (string) $item['description'] : $def['description'],
'name' => isset( $item['name'] ) && $item['name'] !== '' ? (string) $item['name'] : $def['name'],
'name_en' => isset( $item['name_en'] ) ? (string) $item['name_en'] : '',
'pricePerDay' => isset( $item['pricePerDay'] ) ? (float) $item['pricePerDay'] : (float) $def['pricePerDay'],
'active' => isset( $item['active'] ) ? (bool) $item['active'] : (bool) $def['active'],
'description' => isset( $item['description'] ) ? (string) $item['description'] : $def['description'],
'description_en' => isset( $item['description_en'] ) ? (string) $item['description_en'] : '',
);
}
return $out;
@@ -71,8 +220,8 @@ class Carei_Admin_Panel {
public function register_protection_packages_page() {
add_submenu_page(
'edit.php?post_type=' . self::POST_TYPE,
'Pakiety ochronne',
'Pakiety ochronne',
__( 'Pakiety ochronne', 'carei-reservation' ),
__( 'Pakiety ochronne', 'carei-reservation' ),
'manage_options',
'carei-protection-packages',
array( $this, 'render_protection_packages_page' )
@@ -81,16 +230,16 @@ class Carei_Admin_Panel {
public function render_protection_packages_page() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( 'Brak uprawnień.' );
wp_die( esc_html__( 'Brak uprawnień.', 'carei-reservation' ) );
}
$data = self::get_protection_packages();
$saved = isset( $_GET['carei_saved'] ) && $_GET['carei_saved'] === '1';
?>
<div class="wrap">
<h1>Pakiety ochronne</h1>
<p>Konfiguracja pakietów wyświetlanych w sekcji <strong>Pakiety ochronne</strong> formularza rezerwacji. Cena podawana jest za dobę — total = cena × liczba dób rezerwacji.</p>
<h1><?php esc_html_e( 'Pakiety ochronne', 'carei-reservation' ); ?></h1>
<p><?php echo wp_kses( __( 'Konfiguracja pakietów wyświetlanych w sekcji <strong>Pakiety ochronne</strong> formularza rezerwacji. Cena podawana jest za dobę — total = cena × liczba dób rezerwacji.', 'carei-reservation' ), array( 'strong' => array() ) ); ?></p>
<?php if ( $saved ) : ?>
<div class="notice notice-success is-dismissible"><p>Zapisano.</p></div>
<div class="notice notice-success is-dismissible"><p><?php esc_html_e( 'Zapisano.', 'carei-reservation' ); ?></p></div>
<?php endif; ?>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="carei-protection-form">
<input type="hidden" name="action" value="carei_save_protection_packages">
@@ -100,29 +249,43 @@ class Carei_Admin_Panel {
$pkg = $data[ $key ];
?>
<div class="carei-protection-card">
<h2>Pakiet <?php echo esc_html( $label ); ?></h2>
<h2><?php echo esc_html( sprintf( __( 'Pakiet %s', 'carei-reservation' ), $label ) ); ?></h2>
<table class="form-table">
<tr>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_name">Nazwa wyświetlana</label></th>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_name"><?php esc_html_e( 'Nazwa wyświetlana (PL)', 'carei-reservation' ); ?></label></th>
<td><input type="text" id="carei_<?php echo esc_attr( $key ); ?>_name" name="packages[<?php echo esc_attr( $key ); ?>][name]" value="<?php echo esc_attr( $pkg['name'] ); ?>" class="regular-text" required></td>
</tr>
<tr>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_price">Cena za dobę (zł)</label></th>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_name_en"><?php esc_html_e( 'Nazwa wyświetlana (EN)', 'carei-reservation' ); ?></label></th>
<td>
<input type="text" id="carei_<?php echo esc_attr( $key ); ?>_name_en" name="packages[<?php echo esc_attr( $key ); ?>][name_en]" value="<?php echo esc_attr( $pkg['name_en'] ); ?>" class="regular-text" placeholder="<?php echo esc_attr__( 'Np. SOFT Protection', 'carei-reservation' ); ?>">
<p class="description"><?php esc_html_e( 'Puste = fallback do wersji polskiej.', 'carei-reservation' ); ?></p>
</td>
</tr>
<tr>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_price"><?php esc_html_e( 'Cena za dobę (zł)', 'carei-reservation' ); ?></label></th>
<td><input type="number" id="carei_<?php echo esc_attr( $key ); ?>_price" name="packages[<?php echo esc_attr( $key ); ?>][pricePerDay]" value="<?php echo esc_attr( $pkg['pricePerDay'] ); ?>" min="0" step="0.01" class="small-text" required></td>
</tr>
<tr>
<th>Status</th>
<td><label><input type="checkbox" name="packages[<?php echo esc_attr( $key ); ?>][active]" value="1" <?php checked( $pkg['active'] ); ?>> Aktywny (widoczny w modalu)</label></td>
<th><?php esc_html_e( 'Status', 'carei-reservation' ); ?></th>
<td><label><input type="checkbox" name="packages[<?php echo esc_attr( $key ); ?>][active]" value="1" <?php checked( $pkg['active'] ); ?>> <?php esc_html_e( 'Aktywny (widoczny w modalu)', 'carei-reservation' ); ?></label></td>
</tr>
<tr>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_desc">Opis / zakres usług</label></th>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_desc"><?php esc_html_e( 'Opis / zakres usług (PL)', 'carei-reservation' ); ?></label></th>
<td><textarea id="carei_<?php echo esc_attr( $key ); ?>_desc" name="packages[<?php echo esc_attr( $key ); ?>][description]" rows="3" cols="60" class="large-text"><?php echo esc_textarea( $pkg['description'] ); ?></textarea></td>
</tr>
<tr>
<th><label for="carei_<?php echo esc_attr( $key ); ?>_desc_en"><?php esc_html_e( 'Opis / zakres usług (EN)', 'carei-reservation' ); ?></label></th>
<td>
<textarea id="carei_<?php echo esc_attr( $key ); ?>_desc_en" name="packages[<?php echo esc_attr( $key ); ?>][description_en]" rows="3" cols="60" class="large-text" placeholder="<?php echo esc_attr__( 'Basic protection package...', 'carei-reservation' ); ?>"><?php echo esc_textarea( $pkg['description_en'] ); ?></textarea>
<p class="description"><?php esc_html_e( 'Puste = fallback do wersji polskiej.', 'carei-reservation' ); ?></p>
</td>
</tr>
</table>
</div>
<?php endforeach; ?>
<?php submit_button( 'Zapisz pakiety' ); ?>
<?php submit_button( __( 'Zapisz pakiety', 'carei-reservation' ) ); ?>
</form>
</div>
<style>
@@ -134,10 +297,10 @@ class Carei_Admin_Panel {
public function handle_protection_packages_save() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( 'Brak uprawnień.' );
wp_die( esc_html__( 'Brak uprawnień.', 'carei-reservation' ) );
}
if ( ! isset( $_POST['carei_protection_nonce'] ) || ! wp_verify_nonce( $_POST['carei_protection_nonce'], 'carei_protection_packages' ) ) {
wp_die( 'Nieprawidłowy token.' );
wp_die( esc_html__( 'Nieprawidłowy token.', 'carei-reservation' ) );
}
$input = isset( $_POST['packages'] ) && is_array( $_POST['packages'] ) ? $_POST['packages'] : array();
@@ -145,16 +308,20 @@ class Carei_Admin_Panel {
$clean = array();
foreach ( $defaults as $key => $def ) {
$raw = isset( $input[ $key ] ) && is_array( $input[ $key ] ) ? $input[ $key ] : array();
$name = isset( $raw['name'] ) ? sanitize_text_field( wp_unslash( $raw['name'] ) ) : $def['name'];
$price = isset( $raw['pricePerDay'] ) ? (float) $raw['pricePerDay'] : 0;
$name = isset( $raw['name'] ) ? sanitize_text_field( wp_unslash( $raw['name'] ) ) : $def['name'];
$name_en = isset( $raw['name_en'] ) ? sanitize_text_field( wp_unslash( $raw['name_en'] ) ) : '';
$price = isset( $raw['pricePerDay'] ) ? (float) $raw['pricePerDay'] : 0;
if ( $price < 0 ) { $price = 0; }
$active = ! empty( $raw['active'] );
$desc = isset( $raw['description'] ) ? sanitize_textarea_field( wp_unslash( $raw['description'] ) ) : '';
$active = ! empty( $raw['active'] );
$desc = isset( $raw['description'] ) ? sanitize_textarea_field( wp_unslash( $raw['description'] ) ) : '';
$desc_en = isset( $raw['description_en'] ) ? sanitize_textarea_field( wp_unslash( $raw['description_en'] ) ) : '';
$clean[ $key ] = array(
'name' => $name !== '' ? $name : $def['name'],
'pricePerDay' => $price,
'active' => $active,
'description' => $desc,
'name' => $name !== '' ? $name : $def['name'],
'name_en' => $name_en,
'pricePerDay' => $price,
'active' => $active,
'description' => $desc,
'description_en' => $desc_en,
);
}
update_option( self::PROTECTION_OPTION, $clean );
@@ -174,15 +341,15 @@ class Carei_Admin_Panel {
public function register_post_type() {
register_post_type( self::POST_TYPE, array(
'labels' => array(
'name' => 'Rezerwacje',
'singular_name' => 'Rezerwacja',
'menu_name' => 'Rezerwacje',
'all_items' => 'Wszystkie rezerwacje',
'view_item' => 'Zobacz rezerwację',
'edit_item' => 'Szczegóły rezerwacji',
'search_items' => 'Szukaj rezerwacji',
'not_found' => 'Nie znaleziono rezerwacji',
'not_found_in_trash' => 'Brak rezerwacji w koszu',
'name' => __( 'Rezerwacje', 'carei-reservation' ),
'singular_name' => __( 'Rezerwacja', 'carei-reservation' ),
'menu_name' => __( 'Rezerwacje', 'carei-reservation' ),
'all_items' => __( 'Wszystkie rezerwacje', 'carei-reservation' ),
'view_item' => __( 'Zobacz rezerwację', 'carei-reservation' ),
'edit_item' => __( 'Szczegóły rezerwacji', 'carei-reservation' ),
'search_items' => __( 'Szukaj rezerwacji', 'carei-reservation' ),
'not_found' => __( 'Nie znaleziono rezerwacji', 'carei-reservation' ),
'not_found_in_trash' => __( 'Brak rezerwacji w koszu', 'carei-reservation' ),
),
'public' => false,
'show_ui' => true,
@@ -202,13 +369,13 @@ class Carei_Admin_Panel {
public function admin_columns( $columns ) {
return array(
'cb' => '<input type="checkbox" />',
'reservation_no' => 'Nr rezerwacji',
'client' => 'Klient',
'segment' => 'Segment',
'dates' => 'Daty',
'branch' => 'Oddział',
'carei_status' => 'Status',
'date' => 'Data',
'reservation_no' => __( 'Nr rezerwacji', 'carei-reservation' ),
'client' => __( 'Klient', 'carei-reservation' ),
'segment' => __( 'Segment', 'carei-reservation' ),
'dates' => __( 'Daty', 'carei-reservation' ),
'branch' => __( 'Oddział', 'carei-reservation' ),
'carei_status' => __( 'Status', 'carei-reservation' ),
'date' => __( 'Data', 'carei-reservation' ),
);
}
@@ -250,7 +417,7 @@ class Carei_Admin_Panel {
printf(
'<span class="carei-status-badge" style="background:%s;">%s</span>',
esc_attr( $info['color'] ),
esc_html( $info['label'] )
esc_html( self::get_status_label( $status ) )
);
break;
}
@@ -264,13 +431,13 @@ class Carei_Admin_Panel {
}
$current = isset( $_GET['carei_status'] ) ? sanitize_text_field( $_GET['carei_status'] ) : '';
echo '<select name="carei_status">';
echo '<option value="">Wszystkie statusy</option>';
echo '<option value="">' . esc_html__( 'Wszystkie statusy', 'carei-reservation' ) . '</option>';
foreach ( self::$statuses as $key => $info ) {
printf(
'<option value="%s"%s>%s</option>',
esc_attr( $key ),
selected( $current, $key, false ),
esc_html( $info['label'] )
esc_html( self::get_status_label( $key ) )
);
}
echo '</select>';
@@ -306,7 +473,7 @@ class Carei_Admin_Panel {
public function add_meta_boxes() {
add_meta_box(
'carei_reservation_details',
'Szczegóły rezerwacji',
__( 'Szczegóły rezerwacji', 'carei-reservation' ),
array( $this, 'render_meta_box' ),
self::POST_TYPE,
'normal',
@@ -345,7 +512,14 @@ class Carei_Admin_Panel {
$price = isset( $protection['pricePerDay'] ) ? (float) $protection['pricePerDay'] : 0;
$days = isset( $protection['days'] ) ? (int) $protection['days'] : 0;
$total = isset( $protection['total'] ) ? (float) $protection['total'] : ( $price * $days );
$protection_str = sprintf( '%s — %s zł/doba × %d = %s zł', $name, number_format( $price, 2, ',', ' ' ), $days, number_format( $total, 2, ',', ' ' ) );
$protection_str = sprintf(
/* translators: 1: package name, 2: price per day, 3: number of days, 4: total */
__( '%1$s — %2$s zł/doba × %3$d = %4$s zł', 'carei-reservation' ),
$name,
number_format( $price, 2, ',', ' ' ),
$days,
number_format( $total, 2, ',', ' ' )
);
}
$address = $meta['address'] ? json_decode( $meta['address'], true ) : null;
@@ -373,34 +547,34 @@ class Carei_Admin_Panel {
?>
<table class="carei-meta-table">
<tr><th>Nr rezerwacji</th><td><?php echo esc_html( $meta['reservation_no'] ?: '—' ); ?></td></tr>
<tr><th>ID rezerwacji (Softra)</th><td><?php echo esc_html( $meta['reservation_id'] ?: '—' ); ?></td></tr>
<tr><th>ID klienta (Softra)</th><td><?php echo esc_html( $meta['customer_id'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Nr rezerwacji', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['reservation_no'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'ID rezerwacji (Softra)', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['reservation_id'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'ID klienta (Softra)', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['customer_id'] ?: '—' ); ?></td></tr>
<tr class="carei-meta-divider"><td colspan="2"><hr></td></tr>
<tr><th>Segment</th><td><?php echo esc_html( $meta['segment'] ?: '—' ); ?></td></tr>
<tr><th>Data od</th><td><?php echo esc_html( $from_fmt ); ?></td></tr>
<tr><th>Data do</th><td><?php echo esc_html( $to_fmt ); ?></td></tr>
<tr><th>Oddział odbioru</th><td><?php echo esc_html( $meta['pickup_branch'] ?: '—' ); ?></td></tr>
<tr><th>Oddział zwrotu</th><td><?php echo esc_html( $meta['return_branch'] ?: $meta['pickup_branch'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Segment', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['segment'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Data od', 'carei-reservation' ); ?></th><td><?php echo esc_html( $from_fmt ); ?></td></tr>
<tr><th><?php esc_html_e( 'Data do', 'carei-reservation' ); ?></th><td><?php echo esc_html( $to_fmt ); ?></td></tr>
<tr><th><?php esc_html_e( 'Oddział odbioru', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['pickup_branch'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Oddział zwrotu', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['return_branch'] ?: $meta['pickup_branch'] ?: '—' ); ?></td></tr>
<tr class="carei-meta-divider"><td colspan="2"><hr></td></tr>
<tr><th>Imię</th><td><?php echo esc_html( $meta['first_name'] ?: '—' ); ?></td></tr>
<tr><th>Nazwisko</th><td><?php echo esc_html( $meta['last_name'] ?: '—' ); ?></td></tr>
<tr><th>Email</th><td><?php echo esc_html( $meta['email'] ?: '—' ); ?></td></tr>
<tr><th>Telefon</th><td><?php echo esc_html( $meta['phone'] ?: '—' ); ?></td></tr>
<tr><th>PESEL</th><td><?php echo esc_html( $meta['pesel'] ?: '—' ); ?></td></tr>
<tr><th>Adres</th><td><?php echo esc_html( $address_str ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Imię', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['first_name'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Nazwisko', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['last_name'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Email', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['email'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Telefon', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['phone'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'PESEL', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['pesel'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Adres', 'carei-reservation' ); ?></th><td><?php echo esc_html( $address_str ?: '—' ); ?></td></tr>
<tr class="carei-meta-divider"><td colspan="2"><hr></td></tr>
<tr><th>Opcje dodatkowe</th><td><?php echo esc_html( $extras_str ?: 'Brak' ); ?></td></tr>
<tr><th>Pakiet ochronny</th><td><?php echo esc_html( $protection_str ?: 'Brak' ); ?></td></tr>
<tr><th>Wiadomość</th><td><?php echo esc_html( $meta['comments'] ?: '—' ); ?></td></tr>
<tr><th><?php esc_html_e( 'Opcje dodatkowe', 'carei-reservation' ); ?></th><td><?php echo esc_html( $extras_str ?: __( 'Brak', 'carei-reservation' ) ); ?></td></tr>
<tr><th><?php esc_html_e( 'Pakiet ochronny', 'carei-reservation' ); ?></th><td><?php echo esc_html( $protection_str ?: __( 'Brak', 'carei-reservation' ) ); ?></td></tr>
<tr><th><?php esc_html_e( 'Wiadomość', 'carei-reservation' ); ?></th><td><?php echo esc_html( $meta['comments'] ?: '—' ); ?></td></tr>
<tr class="carei-meta-divider"><td colspan="2"><hr></td></tr>
<tr>
<th>Status</th>
<th><?php esc_html_e( 'Status', 'carei-reservation' ); ?></th>
<td>
<select name="carei_status">
<?php foreach ( self::$statuses as $key => $info ) : ?>
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $meta['status'], $key ); ?>>
<?php echo esc_html( $info['label'] ); ?>
<?php echo esc_html( self::get_status_label( $key ) ); ?>
</option>
<?php endforeach; ?>
</select>
@@ -513,7 +687,13 @@ class Carei_Admin_Panel {
$first_name = isset( $driver['firstName'] ) ? $driver['firstName'] : '';
$last_name = isset( $driver['lastName'] ) ? $driver['lastName'] : '';
$title = sprintf( 'Rezerwacja #%s — %s %s', $reservation_no ?: $reservation_id, $first_name, $last_name );
$title = sprintf(
/* translators: 1: reservation number or ID, 2: first name, 3: last name */
__( 'Rezerwacja #%1$s — %2$s %3$s', 'carei-reservation' ),
$reservation_no ?: $reservation_id,
$first_name,
$last_name
);
$post_id = wp_insert_post( array(
'post_type' => self::POST_TYPE,

View File

@@ -20,7 +20,7 @@ class Carei_Branches_Widget extends \Elementor\Widget_Base {
}
public function get_title() {
return 'Carei Branches';
return esc_html__( 'Carei Branches', 'carei-reservation' );
}
public function get_icon() {
@@ -92,11 +92,11 @@ class Carei_Branches_Widget extends \Elementor\Widget_Base {
if ( $street ) {
$street_lower = mb_strtolower( $street, 'UTF-8' );
$has_prefix = preg_match( '/^(ul\.|al\.|pl\.|os\.)/u', $street_lower );
$street = $has_prefix ? $street : 'ul. ' . $street;
$street = $has_prefix ? $street : sprintf( /* translators: %s: street name */ __( 'ul. %s', 'carei-reservation' ), $street );
}
$result[] = array(
'name' => 'Oddział ' . $display_city,
'name' => sprintf( /* translators: %s: city name */ __( 'Oddział %s', 'carei-reservation' ), $display_city ),
'street' => $street,
'zipCity' => trim( $zip . ' ' . $api_city_tc ),
);

View File

@@ -13,7 +13,7 @@ class Carei_Cities_Widget extends \Elementor\Widget_Base {
}
public function get_title() {
return 'Carei Cities';
return esc_html__( 'Carei Cities', 'carei-reservation' );
}
public function get_icon() {

View File

@@ -13,7 +13,7 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
}
public function get_title() {
return 'Carei Reservation';
return esc_html__( 'Carei Reservation', 'carei-reservation' );
}
public function get_icon() {
@@ -34,14 +34,14 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
protected function register_controls() {
$this->start_controls_section( 'content_section', array(
'label' => 'Przycisk rezerwacji',
'label' => esc_html__( 'Przycisk rezerwacji', 'carei-reservation' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
) );
$this->add_control( 'button_text', array(
'label' => 'Tekst przycisku',
'label' => esc_html__( 'Tekst przycisku', 'carei-reservation' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => 'Złóż zapytanie o rezerwację',
'default' => esc_html__( 'Złóż zapytanie o rezerwację', 'carei-reservation' ),
) );
$this->end_controls_section();
@@ -59,12 +59,12 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-modal-overlay" data-carei-modal role="dialog" aria-modal="true" aria-labelledby="carei-modal-title">
<div class="carei-modal">
<div class="carei-modal__scroll">
<span role="button" tabindex="0" class="carei-modal-close" data-carei-close-modal aria-label="Zamknij formularz">
<span role="button" tabindex="0" class="carei-modal-close" data-carei-close-modal aria-label="<?php echo esc_attr__( 'Zamknij formularz', 'carei-reservation' ); ?>">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 5L5 15M5 5l10 10" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
</svg>
</span>
<h2 class="carei-modal-title" id="carei-modal-title">Wypełnij formularz rezerwacji<span>.</span></h2>
<h2 class="carei-modal-title" id="carei-modal-title"><?php esc_html_e( 'Wypełnij formularz rezerwacji', 'carei-reservation' ); ?><span>.</span></h2>
<form class="carei-form" id="carei-reservation-form" novalidate>
@@ -74,7 +74,7 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-form__field">
<div class="carei-form__select-wrap">
<select id="carei-segment" name="segment" required>
<option value="" disabled selected>Wybierz segment pojazdu</option>
<option value="" disabled selected><?php esc_html_e( 'Wybierz segment pojazdu', 'carei-reservation' ); ?></option>
</select>
<svg class="carei-form__select-arrow" width="16" height="16" viewBox="0 0 16 16"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>
</div>
@@ -82,27 +82,27 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-form__field carei-form__field--date">
<div class="carei-form__date-wrap">
<svg class="carei-form__date-icon" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="3" width="11" height="10" rx="0.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M11 1.5v2M5 1.5v2M2.5 5.5h11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/></svg>
<label class="carei-form__date-label" for="carei-date-from">Od kiedy?</label>
<label class="carei-form__date-label" for="carei-date-from"><?php esc_html_e( 'Od kiedy?', 'carei-reservation' ); ?></label>
<input type="datetime-local" id="carei-date-from" name="dateFrom" class="carei-form__input carei-form__input--date" required>
</div>
</div>
<div class="carei-form__field carei-form__field--date">
<div class="carei-form__date-wrap">
<svg class="carei-form__date-icon" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="3" width="11" height="10" rx="0.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M11 1.5v2M5 1.5v2M2.5 5.5h11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/></svg>
<label class="carei-form__date-label" for="carei-date-to">Do kiedy?</label>
<label class="carei-form__date-label" for="carei-date-to"><?php esc_html_e( 'Do kiedy?', 'carei-reservation' ); ?></label>
<input type="datetime-local" id="carei-date-to" name="dateTo" class="carei-form__input carei-form__input--date" required>
</div>
</div>
</div>
<div class="carei-form__days-count" id="carei-days-count">Wybrano: <strong>0 dni</strong></div>
<div class="carei-form__days-count" id="carei-days-count"><?php esc_html_e( 'Wybrano:', 'carei-reservation' ); ?> <strong><?php esc_html_e( '0 dni', 'carei-reservation' ); ?></strong></div>
<div class="carei-form__row carei-form__row--pickup">
<div class="carei-form__field">
<div class="carei-form__select-wrap carei-form__select-wrap--icon">
<svg class="carei-form__icon-pin" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 1C5.24 1 3 3.24 3 6c0 3.75 5 9 5 9s5-5.25 5-9c0-2.76-2.24-5-5-5zm0 7a2 2 0 110-4 2 2 0 010 4z" fill="currentColor"/></svg>
<select id="carei-pickup-branch" name="pickupBranch" required>
<option value="" disabled selected>Miejsce odbioru</option>
<option value="" disabled selected><?php esc_html_e( 'Miejsce odbioru', 'carei-reservation' ); ?></option>
</select>
<svg class="carei-form__select-arrow" width="16" height="16" viewBox="0 0 16 16"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>
</div>
@@ -112,7 +112,7 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<span class="carei-form__checkbox-box">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7l3.5 3.5L12 4" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
<span class="carei-form__checkbox-text">Zwrot w tej samej lokalizacji</span>
<span class="carei-form__checkbox-text"><?php esc_html_e( 'Zwrot w tej samej lokalizacji', 'carei-reservation' ); ?></span>
</label>
</div>
@@ -120,7 +120,7 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-form__select-wrap carei-form__select-wrap--icon">
<svg class="carei-form__icon-pin" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 1C5.24 1 3 3.24 3 6c0 3.75 5 9 5 9s5-5.25 5-9c0-2.76-2.24-5-5-5zm0 7a2 2 0 110-4 2 2 0 010 4z" fill="currentColor"/></svg>
<select id="carei-return-branch" name="returnBranch">
<option value="" disabled selected>Miejsce zwrotu</option>
<option value="" disabled selected><?php esc_html_e( 'Miejsce zwrotu', 'carei-reservation' ); ?></option>
</select>
<svg class="carei-form__select-arrow" width="16" height="16" viewBox="0 0 16 16"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>
</div>
@@ -130,18 +130,18 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<!-- Ubezpieczenie + Opcje dodatkowe (ukryte do wybrania segmentu i miejsca odbioru) -->
<div id="carei-extras-wrapper" class="carei-form__extras-wrapper" style="display:none;">
<div class="carei-form__divider"><span>Wyjazd zagraniczny</span></div>
<div class="carei-form__divider"><span><?php esc_html_e( 'Wyjazd zagraniczny', 'carei-reservation' ); ?></span></div>
<div class="carei-form__section" id="carei-abroad-section" style="display:none;">
<label class="carei-form__checkbox-label carei-form__checkbox-label--abroad">
<input type="checkbox" id="carei-abroad-toggle" name="abroadToggle">
<span class="carei-form__checkbox-box"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7l3.5 3.5L12 4" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
<span>Wyjazd poza granicę Polski do:</span>
<span><?php esc_html_e( 'Wyjazd poza granicę Polski do:', 'carei-reservation' ); ?></span>
</label>
<div id="carei-abroad-search" class="carei-abroad" style="display:none;">
<div class="carei-abroad__input-wrap">
<svg class="carei-abroad__plus-icon" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2v12M2 8h12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<input type="text" id="carei-abroad-input" class="carei-abroad__input" placeholder="Wyszukaj i dodaj kraj na trasie">
<span role="button" tabindex="0" class="carei-abroad__clear" id="carei-abroad-clear" title="Wyczyść">
<input type="text" id="carei-abroad-input" class="carei-abroad__input" placeholder="<?php echo esc_attr__( 'Wyszukaj i dodaj kraj na trasie', 'carei-reservation' ); ?>">
<span role="button" tabindex="0" class="carei-abroad__clear" id="carei-abroad-clear" title="<?php echo esc_attr__( 'Wyczyść', 'carei-reservation' ); ?>">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 3l8 8M11 3l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
</span>
</div>
@@ -150,18 +150,14 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
</div>
</div>
<div class="carei-form__divider"><span>Pakiety ochronne</span></div>
<div class="carei-form__divider"><span><?php esc_html_e( 'Pakiety ochronne', 'carei-reservation' ); ?></span></div>
<div class="carei-form__section">
<div class="carei-form__row carei-form__row--protection-packages" id="carei-protection-packages-container">
<!-- Dynamicznie z panelu WP (SOFT, PREMIUM) -->
</div>
<div class="carei-form__protection-divider" aria-hidden="true"></div>
<div class="carei-form__row" id="carei-insurance-container">
<!-- Dynamicznie z API pricelist -->
</div>
</div>
<div class="carei-form__divider"><span>Opcje dodatkowe</span></div>
<div class="carei-form__divider"><span><?php esc_html_e( 'Opcje dodatkowe', 'carei-reservation' ); ?></span></div>
<div class="carei-form__section">
<div class="carei-form__row" id="carei-extras-container">
<!-- Dynamicznie z API pricelist -->
@@ -171,20 +167,20 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
</div>
<!-- Dane najemcy -->
<div class="carei-form__divider"><span>Dane najemcy</span></div>
<div class="carei-form__divider"><span><?php esc_html_e( 'Dane najemcy', 'carei-reservation' ); ?></span></div>
<div class="carei-form__section">
<div class="carei-form__row">
<div class="carei-form__field">
<div class="carei-form__float-wrap">
<input type="text" id="carei-firstname" name="firstName" class="carei-form__input carei-form__input--float" placeholder=" " required>
<label class="carei-form__float-label" for="carei-firstname">Imię</label>
<label class="carei-form__float-label" for="carei-firstname"><?php esc_html_e( 'Imię', 'carei-reservation' ); ?></label>
</div>
</div>
<div class="carei-form__field">
<div class="carei-form__float-wrap">
<input type="text" id="carei-lastname" name="lastName" class="carei-form__input carei-form__input--float" placeholder=" " required>
<label class="carei-form__float-label" for="carei-lastname">Nazwisko</label>
<label class="carei-form__float-label" for="carei-lastname"><?php esc_html_e( 'Nazwisko', 'carei-reservation' ); ?></label>
</div>
</div>
</div>
@@ -193,12 +189,12 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-form__field">
<div class="carei-form__float-wrap">
<input type="email" id="carei-email" name="email" class="carei-form__input carei-form__input--float" placeholder=" " required>
<label class="carei-form__float-label" for="carei-email">Adres e-mail</label>
<label class="carei-form__float-label" for="carei-email"><?php esc_html_e( 'Adres e-mail', 'carei-reservation' ); ?></label>
</div>
</div>
<div class="carei-form__field">
<div class="carei-form__phone-wrap">
<label class="carei-form__phone-label" for="carei-phone">Nr telefonu</label>
<label class="carei-form__phone-label" for="carei-phone"><?php esc_html_e( 'Nr telefonu', 'carei-reservation' ); ?></label>
<div class="carei-form__phone-row">
<div class="carei-form__phone-prefix">
<span class="carei-form__phone-flag">🇵🇱</span>
@@ -212,7 +208,7 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-form__field carei-form__field--full">
<textarea id="carei-message" name="message" class="carei-form__textarea" placeholder="Twoja wiadomość dotycząca rezerwacji" rows="4"></textarea>
<textarea id="carei-message" name="message" class="carei-form__textarea" placeholder="<?php echo esc_attr__( 'Twoja wiadomość dotycząca rezerwacji', 'carei-reservation' ); ?>" rows="4"></textarea>
</div>
</div>
@@ -223,23 +219,23 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<span class="carei-form__checkbox-box">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7l3.5 3.5L12 4" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
<span class="carei-form__checkbox-text">Zgadzam się na <a href="/polityka-prywatnosci/" target="_blank">Politykę Prywatności</a></span>
<span class="carei-form__checkbox-text"><?php echo wp_kses( __( 'Zgadzam się na <a href="/polityka-prywatnosci/" target="_blank">Politykę Prywatności</a>', 'carei-reservation' ), array( 'a' => array( 'href' => array(), 'target' => array() ) ) ); ?></span>
</label>
<button type="submit" class="carei-form__submit" aria-busy="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
Wyślij
<?php esc_html_e( 'Wyślij', 'carei-reservation' ); ?>
</button>
</div>
<div class="carei-form__error-summary" id="carei-error-summary" style="display:none;">
Uzupełnij wymagane pola zaznaczone na czerwono.
<?php esc_html_e( 'Uzupełnij wymagane pola zaznaczone na czerwono.', 'carei-reservation' ); ?>
</div>
</form>
<!-- Podsumowanie kosztów (po submit) -->
<div id="carei-summary-overlay" class="carei-summary" style="display:none;">
<h3 class="carei-summary__title" tabindex="-1">Podsumowanie rezerwacji<span>.</span></h3>
<h3 class="carei-summary__title" tabindex="-1"><?php esc_html_e( 'Podsumowanie rezerwacji', 'carei-reservation' ); ?><span>.</span></h3>
<div class="carei-summary__details" id="carei-summary-details"></div>
<div class="carei-summary__table" id="carei-summary-table"></div>
<div class="carei-summary__total" id="carei-summary-total"></div>
@@ -247,11 +243,11 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-summary__actions">
<button type="button" class="carei-summary__btn carei-summary__btn--back" id="carei-summary-back">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M19 12H5M12 19l-7-7 7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
Wróć do formularza
<?php esc_html_e( 'Wróć do formularza', 'carei-reservation' ); ?>
</button>
<button type="button" class="carei-summary__btn carei-summary__btn--confirm" id="carei-summary-confirm" aria-busy="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
Potwierdź rezerwację
<?php esc_html_e( 'Potwierdź rezerwację', 'carei-reservation' ); ?>
</button>
</div>
</div>
@@ -261,10 +257,10 @@ class Carei_Reservation_Widget extends \Elementor\Widget_Base {
<div class="carei-success__icon">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none"><path d="M20 6L9 17l-5-5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<h3 class="carei-success__title" tabindex="-1">Zamówienie złożone!</h3>
<h3 class="carei-success__title" tabindex="-1"><?php esc_html_e( 'Zamówienie złożone!', 'carei-reservation' ); ?></h3>
<p class="carei-success__number" id="carei-success-number"></p>
<p class="carei-success__message">Oczekuj na kontakt z wypożyczalnią</p>
<button type="button" class="carei-success__close" id="carei-success-close">Zamknij</button>
<p class="carei-success__message"><?php esc_html_e( 'Oczekuj na kontakt z wypożyczalnią', 'carei-reservation' ); ?></p>
<button type="button" class="carei-success__close" id="carei-success-close"><?php esc_html_e( 'Zamknij', 'carei-reservation' ); ?></button>
</div>
</div><!-- .carei-modal__scroll -->

View File

@@ -63,7 +63,7 @@ class Carei_Map_Widget extends \Elementor\Widget_Base {
}
public function get_title() {
return 'Carei Map';
return esc_html__( 'Carei Map', 'carei-reservation' );
}
public function get_icon() {
@@ -169,11 +169,11 @@ class Carei_Map_Widget extends \Elementor\Widget_Base {
$api_city = isset( $b['city'] ) ? trim( $b['city'] ) : '';
$api_city_title = mb_convert_case( $api_city, MB_CASE_TITLE, 'UTF-8' );
$address_lines = array( 'Oddział ' . $display_city );
$address_lines = array( sprintf( /* translators: %s: city name */ __( 'Oddział %s', 'carei-reservation' ), $display_city ) );
if ( $street ) {
$street_lower = mb_strtolower( $street, 'UTF-8' );
$has_prefix = preg_match( '/^(ul\.|al\.|pl\.|os\.)/u', $street_lower );
$address_lines[] = $has_prefix ? $street : 'ul. ' . $street;
$address_lines[] = $has_prefix ? $street : sprintf( /* translators: %s: street name */ __( 'ul. %s', 'carei-reservation' ), $street );
}
$zip_city = trim( $zip . ' ' . $api_city_title );
if ( $zip_city ) {

View File

@@ -145,7 +145,7 @@ class Carei_REST_Proxy {
public function check_nonce( WP_REST_Request $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'rest_forbidden', 'Invalid nonce.', array( 'status' => 403 ) );
return new WP_Error( 'rest_forbidden', __( 'Invalid nonce.', 'carei-reservation' ), array( 'status' => 403 ) );
}
return true;
}
@@ -156,7 +156,7 @@ class Carei_REST_Proxy {
private function api() {
$api = Carei_Softra_API::get_instance();
if ( null === $api ) {
return new WP_Error( 'carei_not_configured', 'Softra API not configured.', array( 'status' => 500 ) );
return new WP_Error( 'carei_not_configured', __( 'Softra API not configured.', 'carei-reservation' ), array( 'status' => 500 ) );
}
return $api;
}
@@ -227,12 +227,34 @@ class Carei_REST_Proxy {
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_pricelist(
$pricelists = $api->get_pricelist(
$request->get_param( 'category' ),
$request->get_param( 'dateFrom' ),
$request->get_param( 'dateTo' ),
$request->get_param( 'pickUpLocation' )
) );
);
// Auto-collect PL extra names + per-locale translate (Phase 19).
if ( is_array( $pricelists ) ) {
$locale = $this->resolve_locale( $request );
$translations = Carei_Admin_Panel::get_extras_translations();
foreach ( $pricelists as &$pricelist ) {
if ( ! is_array( $pricelist ) || empty( $pricelist['additionalItems'] ) || ! is_array( $pricelist['additionalItems'] ) ) continue;
foreach ( $pricelist['additionalItems'] as &$item ) {
if ( ! is_array( $item ) || ! isset( $item['name'] ) || ! is_string( $item['name'] ) ) continue;
$pl_name = trim( $item['name'] );
if ( $pl_name === '' ) continue;
Carei_Admin_Panel::remember_extra_name( $pl_name );
if ( $locale === 'en' && isset( $translations[ $pl_name ] ) && $translations[ $pl_name ] !== '' ) {
$item['name'] = $translations[ $pl_name ];
}
}
unset( $item );
}
unset( $pricelist );
}
return $this->respond( $pricelists );
}
public function get_pricing_summary( WP_REST_Request $request ) {
@@ -307,18 +329,36 @@ class Carei_REST_Proxy {
}
public function get_protection_packages( WP_REST_Request $request ) {
$all = Carei_Admin_Panel::get_protection_packages();
$out = array( 'soft' => null, 'premium' => null );
$all = Carei_Admin_Panel::get_protection_packages();
$locale = $this->resolve_locale( $request );
$out = array( 'soft' => null, 'premium' => null );
foreach ( array( 'soft', 'premium' ) as $key ) {
if ( isset( $all[ $key ] ) && ! empty( $all[ $key ]['active'] ) ) {
$pkg = $all[ $key ];
if ( 'en' === $locale ) {
$name = ! empty( $pkg['name_en'] ) ? $pkg['name_en'] : $pkg['name'];
$desc = ! empty( $pkg['description_en'] ) ? $pkg['description_en'] : $pkg['description'];
} else {
$name = $pkg['name'];
$desc = $pkg['description'];
}
$out[ $key ] = array(
'key' => $key,
'name' => $all[ $key ]['name'],
'pricePerDay' => (float) $all[ $key ]['pricePerDay'],
'description' => $all[ $key ]['description'],
'name' => $name,
'pricePerDay' => (float) $pkg['pricePerDay'],
'description' => $desc,
);
}
}
return rest_ensure_response( $out );
}
private function resolve_locale( WP_REST_Request $request ) {
$lang = $request->get_param( 'lang' );
if ( $lang && in_array( strtolower( $lang ), array( 'pl', 'en' ), true ) ) {
return strtolower( $lang );
}
$locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
return ( 0 === strpos( (string) $locale, 'en' ) ) ? 'en' : 'pl';
}
}

View File

@@ -13,7 +13,7 @@ class Carei_Search_Widget extends \Elementor\Widget_Base {
}
public function get_title() {
return 'Carei Search Form';
return esc_html__( 'Carei Search Form', 'carei-reservation' );
}
public function get_icon() {
@@ -37,14 +37,14 @@ class Carei_Search_Widget extends \Elementor\Widget_Base {
protected function render() {
?>
<div class="carei-search-form">
<h2 class="carei-search-form__title">Wypełnij formularz rezerwacji<span>.</span></h2>
<h2 class="carei-search-form__title"><?php esc_html_e( 'Wypełnij formularz rezerwacji', 'carei-reservation' ); ?><span>.</span></h2>
<div class="carei-search-form__fields">
<!-- Segment -->
<div class="carei-search-form__field carei-search-form__field--full">
<div class="carei-search-form__select-wrap">
<select id="carei-search-segment">
<option value="" disabled selected>Wybierz segment</option>
<option value="" disabled selected><?php esc_html_e( 'Wybierz segment', 'carei-reservation' ); ?></option>
</select>
<svg class="carei-search-form__select-arrow" width="16" height="16" viewBox="0 0 16 16"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>
</div>
@@ -55,14 +55,14 @@ class Carei_Search_Widget extends \Elementor\Widget_Base {
<div class="carei-search-form__field">
<div class="carei-search-form__date-wrap">
<svg class="carei-search-form__date-icon" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="3" width="11" height="10" rx="0.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M11 1.5v2M5 1.5v2M2.5 5.5h11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/></svg>
<label class="carei-search-form__date-label" for="carei-search-date-from">Od kiedy?</label>
<label class="carei-search-form__date-label" for="carei-search-date-from"><?php esc_html_e( 'Od kiedy?', 'carei-reservation' ); ?></label>
<input type="datetime-local" id="carei-search-date-from" class="carei-search-form__input carei-search-form__input--date">
</div>
</div>
<div class="carei-search-form__field">
<div class="carei-search-form__date-wrap">
<svg class="carei-search-form__date-icon" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="3" width="11" height="10" rx="0.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M11 1.5v2M5 1.5v2M2.5 5.5h11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/></svg>
<label class="carei-search-form__date-label" for="carei-search-date-to">Do kiedy?</label>
<label class="carei-search-form__date-label" for="carei-search-date-to"><?php esc_html_e( 'Do kiedy?', 'carei-reservation' ); ?></label>
<input type="datetime-local" id="carei-search-date-to" class="carei-search-form__input carei-search-form__input--date">
</div>
</div>
@@ -73,7 +73,7 @@ class Carei_Search_Widget extends \Elementor\Widget_Base {
<div class="carei-search-form__select-wrap carei-search-form__select-wrap--icon">
<svg class="carei-search-form__pin-icon" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 1C5.24 1 3 3.24 3 6c0 3.75 5 9 5 9s5-5.25 5-9c0-2.76-2.24-5-5-5zm0 7a2 2 0 110-4 2 2 0 010 4z" fill="currentColor"/></svg>
<select id="carei-search-pickup">
<option value="" disabled selected>Miejsce odbioru</option>
<option value="" disabled selected><?php esc_html_e( 'Miejsce odbioru', 'carei-reservation' ); ?></option>
</select>
<svg class="carei-search-form__select-arrow" width="16" height="16" viewBox="0 0 16 16"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>
</div>
@@ -86,7 +86,7 @@ class Carei_Search_Widget extends \Elementor\Widget_Base {
<span class="carei-search-form__checkbox-box">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7l3.5 3.5L12 4" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
<span class="carei-search-form__checkbox-text">Zwrot w tej samej lokalizacji</span>
<span class="carei-search-form__checkbox-text"><?php esc_html_e( 'Zwrot w tej samej lokalizacji', 'carei-reservation' ); ?></span>
</label>
</div>
</div>
@@ -94,7 +94,7 @@ class Carei_Search_Widget extends \Elementor\Widget_Base {
<!-- Przycisk -->
<button type="button" class="carei-search-form__submit" id="carei-search-submit">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
Złóż zapytanie o rezerwację
<?php esc_html_e( 'Złóż zapytanie o rezerwację', 'carei-reservation' ); ?>
</button>
</div>
<?php

View File

@@ -137,9 +137,12 @@ class Carei_Softra_API {
}
if ( $res['status'] < 200 || $res['status'] >= 300 ) {
$raw_msg = self::extract_softra_message( $res['body'] );
$mapped = self::map_error_message( $raw_msg );
$message = $mapped !== '' ? $mapped : sprintf( 'Softra API error: HTTP %d', $res['status'] );
return new WP_Error(
'carei_api_error',
'Softra API error: HTTP ' . $res['status'],
$message,
array( 'status' => $res['status'], 'body' => $res['body'] )
);
}
@@ -147,6 +150,69 @@ class Carei_Softra_API {
return $res['body'];
}
/**
* Extract human-readable message from Softra response body.
* Softra returns either JSON with `message` / `error` / `details` field, or raw string.
*/
public static function extract_softra_message( $body ) {
if ( is_array( $body ) ) {
foreach ( array( 'message', 'error', 'details', 'description' ) as $field ) {
if ( ! empty( $body[ $field ] ) && is_string( $body[ $field ] ) ) {
return trim( $body[ $field ] );
}
}
return '';
}
if ( is_string( $body ) && $body !== '' ) {
$decoded = json_decode( $body, true );
if ( is_array( $decoded ) ) {
return self::extract_softra_message( $decoded );
}
return trim( $body );
}
return '';
}
/**
* Map typical Softra PL error messages to localized strings.
* Exact match first, then fuzzy prefix match. Unknown messages passthrough.
*/
public static function map_error_message( $original_message ) {
if ( ! is_string( $original_message ) || '' === trim( $original_message ) ) {
return $original_message;
}
$dict = array(
'Brak dostępnego pojazdu w wybranym terminie' => __( 'Brak dostępnego pojazdu w wybranym terminie. Zmień daty lub segment.', 'carei-reservation' ),
'Nieprawidłowy zakres dat' => __( 'Nieprawidłowy zakres dat', 'carei-reservation' ),
'Nie znaleziono oddziału' => __( 'Nie znaleziono oddziału', 'carei-reservation' ),
'Klient o tych danych już istnieje' => __( 'Klient o tych danych już istnieje w systemie', 'carei-reservation' ),
'Nieprawidłowy numer PESEL' => __( 'Nieprawidłowy numer PESEL', 'carei-reservation' ),
'Cennik wygasł' => __( 'Cennik wygasł. Odśwież formularz i spróbuj ponownie.', 'carei-reservation' ),
'Token wygasł' => __( 'Sesja wygasła. Odśwież stronę.', 'carei-reservation' ),
'Nieprawidłowe dane logowania' => __( 'Błąd autoryzacji API. Skontaktuj się z administratorem.', 'carei-reservation' ),
'Brak uprawnień' => __( 'Brak uprawnień do wykonania operacji.', 'carei-reservation' ),
'Błąd serwera' => __( 'Błąd serwera. Spróbuj ponownie za chwilę.', 'carei-reservation' ),
'Przekroczono limit rezerwacji' => __( 'Przekroczono limit rezerwacji dla tego klienta.', 'carei-reservation' ),
'Nieprawidłowy numer telefonu' => __( 'Podaj poprawny numer telefonu (min. 9 cyfr).', 'carei-reservation' ),
'Wymagane pole' => __( 'To pole jest wymagane.', 'carei-reservation' ),
);
$trimmed = trim( $original_message );
if ( isset( $dict[ $trimmed ] ) ) {
return $dict[ $trimmed ];
}
foreach ( $dict as $pl_key => $translated ) {
if ( 0 === stripos( $trimmed, $pl_key ) ) {
return $translated;
}
}
return $original_message;
}
// ─── Public API Methods ───────────────────────────────────────
public function get_branches() {