rocket-a


git -C '/home/opc/rocketa.git' show 23b23db -- resources/views/admin/ad/regist.blade.php

commit 23b23db7f909c788ebc35f447165aa1e465b24e4
Author: Satoshi Ujihara <satoshi_ujihara@fivegate.jp>
Date:   Wed Nov 12 11:38:20 2025 +0900

    翻訳とクリックURLの仕様変更

diff --git a/resources/views/admin/ad/regist.blade.php b/resources/views/admin/ad/regist.blade.php
index 3ac8e09..d4ef6ce 100644
--- a/resources/views/admin/ad/regist.blade.php
+++ b/resources/views/admin/ad/regist.blade.php
@@ -328,16 +328,19 @@ for ($i = 0; $i < 60; $i++) {
 
             <div class="form-group row m-0 border-bottom">
                 <div class="col-sm-2 px-0 bg-gray d-flex align-items-center">
-                    {{ Form::label('',__('ad-regist.tracking_url').'<span class="d-inline-block" tabindex="0" data-bs-toggle="tooltip" data-bs-html="true" 
-      title="{sid} click unique ID&#13;&#10;{ad_id} ad unique ID&#13;&#10;{client_id} client unique ID&#13;&#10;{media_id} media unique ID&#13;&#10;{media_uid} media user unique ID">
-  <i class="fas fa-question-circle text-primary" style="cursor:pointer;"></i>
-</span><span class="required">'.__('ad-regist.required').'</span>', ['class'=>'px-2 col-form-label'], false) }}
+                    {{ Form::label('',__('ad-regist.tracking_url').'<span class="required">'.__('ad-regist.required').'</span>', ['class'=>'px-2 col-form-label'], false) }}
                 </div>
 
                 <div class="col-sm-10 px-0 d-flex align-items-center">
                     <div class="p-2 w-100">
-                        {{ Form::url('url', $url, ['class'=>'form-control', 'placeholder'=>'https://trackingurl.com?sid={sid}&ad_id={ad_id}&client_id={client_id}&media_id={media_id}&media_uid={media_uid}']) }}
-
+                        {{ Form::url('url', $url, ['autocomplete'=>'off', 'class'=>'form-control url-input', 'placeholder'=>'https://trackingurl.com?sid={sid}&ad_id={ad_id}&client_id={client_id}&media_id={media_id}&media_uid={media_uid}']) }}
+@if(__('common._')=="ja")
+<a href="https://docs.google.com/presentation/d/1e1rC3eeg4i4yChQq_vPD0wjhvOUAKN5Ooiz-GIMMOPU/edit?usp=sharing" target="_blank">help</a>
+@elseif(__('common._')=="kr")
+<a href="https://docs.google.com/presentation/d/1I3Mzu3pzgg5hcPcT8yFAIcBF2NialG6o/edit?usp=sharing&ouid=102540245793827718569&rtpof=true&sd=true" target="_blank">help</a>
+@elseif(__('common._')=="en")
+<a href="https://docs.google.com/presentation/d/1abGic0xBP9sSU8UphCIQrzGc7VTNI8u1/edit?usp=sharing&ouid=102540245793827718569&rtpof=true&sd=true" target="_blank">help</a>
+@endif
                         @if($errors->has('url'))
                             <div class="err_msg mt-2">{{ $errors->first('url') }}</div>
                         @endif
@@ -3980,6 +3983,71 @@ for ($i = 0; $i < 60; $i++) {
         @endif
     {{Form::close()}}
     @endif
+
+<!-- 共通モーダル -->
+<div class="modal fade" id="urlBuilderModal" tabindex="-1" aria-labelledby="urlBuilderModalLabel" aria-hidden="true">
+  <div class="modal-dialog modal-lg">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h5 class="modal-title" id="urlBuilderModalLabel">{{__('ad-regist.url_builder')}}</h5>
+        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{__('ad-regist.close')}}"></button>
+      </div>
+      <div class="modal-body">
+        <form id="urlBuilderForm" class="row g-2">
+          <div class="col-12">
+            <label class="form-label">{{__('ad-regist.domain_example')}}</label>
+            <input type="text" id="ubDomain" class="form-control" placeholder="abr.ge">
+          </div>
+          <div class="col-12">
+            <label class="form-label">{{__('ad-regist.path_note')}}</label>
+            <input type="text" id="ubPath" class="form-control" placeholder="/@appname/rocket_a">
+          </div>
+
+          <div class="col-12 mt-3">
+            <label class="form-label">{{__('ad-regist.query_parameters')}}</label>
+            <div id="kvContainer" class="mb-2">
+              <!-- key/value 行がここに挿入される -->
+            </div>
+            <button type="button" id="addKvBtn" class="btn btn-sm btn-outline-primary">+ {{__('ad-regist.add_parameter')}}</button>
+          </div>
+
+          <div class="col-12">
+            <small class="text-muted">※{{__('ad-regist.empty_keys_ignored')}}</small>
+          </div>
+        </form>
+      </div>
+
+      <div class="modal-footer">
+        <button type="button" id="ubCancel" class="btn btn-secondary" data-bs-dismiss="modal">{{__('ad-regist.cancel')}}</button>
+        <button type="button" id="ubApply" class="btn btn-primary">{{__('ad-regist.confirm')}}</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- テンプレート(非表示) -->
+<template id="kvRowTemplate">
+  <div class="input-group mb-2 kv-row">
+    <input type="text" class="form-control kv-key" placeholder="key">
+    <select  class="form-control kv-value" placeholder="{{__('ad-regist.please_select')}}">
+        <option value="{sid}">{sid}</option>
+        <option value="{ad_id}">{ad_id}</option>
+        <option value="{client_id}">{client_id}</option>
+        <option value="{media_id}">{media_id}</option>
+        <option value="{media_uid}">{media_uid}</option>
+        <option value="{ip}">{ip}</option>
+        <option value="{user_agent}">{user_agent}</option>
+        <option value="{referer}">{referer}</option>
+        <option value="{net_price}">{net_price}</option></var>
+        <option value="{gross_price}">{gross_price}</option></var>
+        <option value="{gross_price_unit}">{gross_price_unit}</option></var>
+    </select>
+    <button type="button" class="btn btn-outline-danger remove-kv-btn" title="{{__('ad-regist.delete')}}">✕</button>
+  </div>
+</template>
+
+
+
 @endsection
 
 @section('respectively_js')
@@ -4417,5 +4485,152 @@ function receivingPeriodDecisionAreaControl()
         $('.receiving_period_decision_area').show();
     }
 }
+
+//トラッキングURL設定 start
+$(function() {
+  // Bootstrap Modal インスタンスを生成(要素は DOM に存在する前提)
+  var urlModalEl = document.getElementById('urlBuilderModal');
+  var urlModal = new bootstrap.Modal(urlModalEl, { backdrop: 'static', keyboard: false });
+
+  var $currentInput = null; // モーダル操作対象の input 要素
+
+  // --- ヘルパー: KV 行を追加 ---
+  function addKvRow(key, value) {
+    var tpl = document.getElementById('kvRowTemplate').content.cloneNode(true);
+    var $row = $(tpl).find('.kv-row');
+    $row.find('.kv-key').val(key || '');
+    $row.find('.kv-value').val(value || '');
+    // remove ボタン
+    $row.find('.remove-kv-btn').on('click', function() {
+      $(this).closest('.kv-row').remove();
+    });
+    $('#kvContainer').append($row);
+  }
+
+  // --- 初期で1行用意 ---
+  function ensureAtLeastOneRow() {
+    if ($('#kvContainer').children().length === 0) addKvRow();
+  }
+
+  // + ボタン
+  $('#addKvBtn').on('click', function() {
+    addKvRow();
+  });
+
+  // input 選択(フォーカス/クリック)でモーダルを開く
+  // 複数あっても対応できるよう class .url-input を使う
+  $(document).on('focus', '.url-input', function() {
+    $currentInput = $(this);
+    openModalWithInputValue($currentInput.val());
+  });
+
+  // 既存値を解析してモーダルにプリセットする
+  function openModalWithInputValue(val) {
+    // クリア
+    $('#ubDomain').val('');
+    $('#ubPath').val('');
+    $('#kvContainer').empty();
+
+    if (val && $.trim(val) !== '') {
+      // URL パース(protocol が無ければ https を仮置き)
+      var tryUrl = val;
+      if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(tryUrl)) {
+        tryUrl = 'https://' + tryUrl;
+      }
+      try {
+        var parsed = new URL(tryUrl);
+        // host は host (ホスト名:ポート) ではなく hostname が望ましい
+        $('#ubDomain').val(parsed.hostname + (parsed.port ? (':' + parsed.port) : ''));
+        // pathname は先頭スラッシュあり
+        $('#ubPath').val(parsed.pathname === '/' ? '' : parsed.pathname);
+        // query params
+        parsed.searchParams.forEach(function(value, key) {
+          addKvRow(key, value);
+        });
+      } catch (e) {
+        // URL でない場合(例: "example.com/path" でパースできないなど)は簡易分解
+        // domain と path をスラッシュで分ける
+        var m = val.match(/^([^\/]+)(\/.*)?$/);
+        if (m) {
+          $('#ubDomain').val(m[1]);
+          $('#ubPath').val(m[2] || '');
+        }
+        // query があればパースする(? が含まれている場合)
+        var qIndex = val.indexOf('?');
+        if (qIndex !== -1) {
+          var qs = val.substring(qIndex + 1);
+          var pairs = qs.split('&');
+          pairs.forEach(function(p) {
+            if (!p) return;
+            var kv = p.split('=');
+            var k = decodeURIComponent(kv[0] || '');
+            var v = decodeURIComponent(kv.slice(1).join('=') || '');
+            addKvRow(k, v);
+          });
+        }
+      }
+    }
+
+    ensureAtLeastOneRow();
+    // モーダル表示
+    urlModal.show();
+  }
+
+  // 決定ボタンの動作: 入力値を URL に組み立てて input に反映
+  $('#ubApply').on('click', function() {
+    var domain = $.trim($('#ubDomain').val() || '');
+    var path = $.trim($('#ubPath').val() || '');
+    // path は先頭に / をつける(空なら空)
+    if (path && path[0] !== '/') path = '/' + path;
+
+    if (!domain) {
+      alert('ドメインを入力してください(例: example.com)');
+      return;
+    }
+
+    // query を収集
+    var params = [];
+    $('#kvContainer .kv-row').each(function() {
+      var k = $.trim($(this).find('.kv-key').val() || '');
+      var v = $(this).find('.kv-value').val() || '';
+      if (k === '') return; // 空キーは無視
+      // encodeURIComponent で値を安全にエンコード
+      params.push(encodeURIComponent(k) + '=' + (v));
+    });
+
+    var query = params.length ? '?' + params.join('&') : '';
+    // デフォルトスキームは https
+    var finalUrl = 'https://' + domain + (path || '') + query;
+
+    // もし input の元の値がスキーム付きで別スキームだった場合、スキームを維持する
+    var original = $currentInput && $currentInput.val();
+    if (original && /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(original)) {
+      try {
+        var origParsed = new URL(original);
+        // 同一ホスト? というチェックはしないで、scheme を維持したい場合だけ置換
+        finalUrl = origParsed.protocol + '//' + domain + (path || '') + query;
+      } catch (e) {
+        // 解析失敗なら無視
+      }
+    }
+
+    // 入力に反映
+    if ($currentInput) {
+      $currentInput.val(finalUrl).trigger('change');
+    }
+
+    // モーダル閉じる
+    urlModal.hide();
+  });
+
+  // モーダルが閉じられたら currentInput をクリア(必要なら)
+  urlModalEl.addEventListener('hidden.bs.modal', function () {
+    $currentInput = null;
+  });
+
+  // 初期状態で KV を1行確保(モーダル毎に表示時に ensureAtLeastOneRow が呼ばれるため冗長ではない)
+  ensureAtLeastOneRow();
+});
+//トラッキングURL設定 end
 </script>
 @endsection

diff.txt · 最終更新: by root