Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

277 строки
16KB

  1. <%
  2. Dim isRemoved, isCustomer, bid, mth, oc, ix, it, indKey2, nextDue
  3. If fv Is Nothing Then Set fv = b
  4. isRemoved = (b("status") & "" = "removed")
  5. isCustomer = (b("is_customer") & "" = "1")
  6. bid = CLng(id)
  7. nextDue = False
  8. If Not IsNull(b("next_action_date")) Then
  9. If IsDate(b("next_action_date")) Then nextDue = (CDate(b("next_action_date")) <= Date)
  10. End If
  11. %>
  12. <% Flash().ShowErrorsIfPresent : Flash().ShowSuccessIfPresent %>
  13. <nav aria-label="breadcrumb">
  14. <ol class="breadcrumb small mb-2">
  15. <li class="breadcrumb-item"><a href="/businesses">Businesses</a></li>
  16. <li class="breadcrumb-item active" aria-current="page"><%= H(b("name")) %></li>
  17. </ol>
  18. </nav>
  19. <div class="d-flex flex-wrap align-items-center gap-2 mb-3">
  20. <h1 class="h3 mb-0"><%= H(b("name")) %></h1>
  21. <span class="badge <%= Businesses_StatusClass(b("status")) %>"><%= Businesses_StatusLabel(b("status")) %></span>
  22. <% If isCustomer Then %><span class="badge text-bg-success">Customer</span><% End If %>
  23. <% If Len(b("industry_name") & "") > 0 Then %><span class="badge text-bg-light border"><%= H(b("industry_name")) %></span><% End If %>
  24. <% For ix = 0 To bizAreas.Count - 1 %><a href="/businesses?area=<%= bizAreas(ix)("id") %>" class="badge text-bg-primary bg-opacity-75 text-decoration-none"><i class="bi bi-geo"></i> <%= H(bizAreas(ix)("name")) %></a><% Next %>
  25. </div>
  26. <% If isRemoved Then %>
  27. <div class="alert alert-dark d-flex justify-content-between align-items-center">
  28. <div>
  29. <strong>Removed</strong><% If Not IsNull(b("removed_at")) Then Response.Write " on " & Date_Fmt(b("removed_at")) %>.
  30. <% If Len(b("removed_reason") & "") > 0 Then %>Reason: <%= H(b("removed_reason")) %><% End If %>
  31. </div>
  32. <form method="post" action="/businesses/<%= bid %>/restore" class="mb-0">
  33. <input type="hidden" name="csrf" value="<%= H(csrf) %>" />
  34. <button type="submit" class="btn btn-sm btn-outline-dark">Restore to list</button>
  35. </form>
  36. </div>
  37. <% ElseIf Not IsNull(b("next_action_date")) Then %>
  38. <div class="alert <% If nextDue Then Response.Write "alert-warning" Else Response.Write "alert-info" %> py-2">
  39. <i class="bi bi-calendar-event"></i> Next contact: <strong><%= Date_Fmt(b("next_action_date")) %></strong><% If nextDue Then Response.Write " &mdash; due" %>
  40. </div>
  41. <% End If %>
  42. <div class="row g-3">
  43. <!-- LEFT: log a touch + history -->
  44. <div class="col-lg-7">
  45. <% If Not isRemoved Then %>
  46. <div class="card shadow-sm mb-3">
  47. <div class="card-body">
  48. <h2 class="h5 mb-3">Log a contact</h2>
  49. <form method="post" action="/businesses/<%= bid %>/log" id="logForm">
  50. <input type="hidden" name="csrf" value="<%= H(csrf) %>" />
  51. <div class="mb-3">
  52. <div class="btn-group" role="group" aria-label="How">
  53. <% For Each mth In Businesses_Methods() %>
  54. <input type="radio" class="btn-check" name="method" id="m_<%= mth(0) %>" value="<%= mth(0) %>" autocomplete="off"<% If mth(0) = "call" Then Response.Write " checked" %> />
  55. <label class="btn btn-outline-primary btn-sm" for="m_<%= mth(0) %>"><%= H(mth(1)) %></label>
  56. <% Next %>
  57. </div>
  58. </div>
  59. <div class="row g-2 mb-2">
  60. <div class="col-md-5">
  61. <label for="outcome" class="form-label small mb-1">Outcome</label>
  62. <select class="form-select form-select-sm" id="outcome" name="outcome">
  63. <option value="">&mdash;</option>
  64. <% For Each oc In Businesses_Outcomes() %>
  65. <option value="<%= oc(0) %>"><%= H(oc(1)) %></option>
  66. <% Next %>
  67. </select>
  68. </div>
  69. <div class="col-6 col-md-3">
  70. <label for="contacted_at" class="form-label small mb-1">Date</label>
  71. <input type="date" class="form-control form-control-sm" id="contacted_at" name="contacted_at" value="<%= today %>" max="<%= Date_Iso(Date + 1) %>" />
  72. </div>
  73. <div class="col-6 col-md-4">
  74. <label for="follow_up_date" class="form-label small mb-1">Contact again on</label>
  75. <input type="date" class="form-control form-control-sm" id="follow_up_date" name="follow_up_date" value="" />
  76. </div>
  77. </div>
  78. <div class="mb-2 small">
  79. <span class="text-muted">Quick:</span>
  80. <button type="button" class="btn btn-link btn-sm p-0 me-2" data-days="3">3 days</button>
  81. <button type="button" class="btn btn-link btn-sm p-0 me-2" data-days="7">1 week</button>
  82. <button type="button" class="btn btn-link btn-sm p-0 me-2" data-days="14">2 weeks</button>
  83. <button type="button" class="btn btn-link btn-sm p-0 me-2" data-days="30">1 month</button>
  84. <button type="button" class="btn btn-link btn-sm p-0 text-secondary" data-days="0">clear</button>
  85. </div>
  86. <div class="mb-3">
  87. <label for="log_notes" class="form-label small mb-1">Notes</label>
  88. <textarea class="form-control form-control-sm" id="log_notes" name="notes" rows="3" maxlength="10000"></textarea>
  89. </div>
  90. <button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-check2"></i> Save contact</button>
  91. <span class="text-muted small ms-2" id="removeHint" hidden>This will remove the business from the list (the notes are kept as the reason).</span>
  92. </form>
  93. </div>
  94. </div>
  95. <% End If %>
  96. <div class="card shadow-sm mb-3">
  97. <div class="card-body">
  98. <h2 class="h5 mb-3">History <span class="text-muted fs-6">(<%= interactions.Count %>)</span></h2>
  99. <% If interactions.Count = 0 Then %>
  100. <p class="text-muted mb-0">No contact logged yet.</p>
  101. <% Else %>
  102. <ul class="list-unstyled mb-0">
  103. <% For ix = 0 To interactions.Count - 1
  104. Set it = interactions(ix) %>
  105. <li class="border-start border-3 ps-3 pb-3">
  106. <div class="d-flex flex-wrap gap-2 align-items-center">
  107. <strong><%= Date_Fmt(it("contacted_at")) %></strong>
  108. <span class="badge text-bg-primary"><%= H(Businesses_Label(Businesses_Methods(), it("method"))) %></span>
  109. <% If Len(it("outcome") & "") > 0 Then %><span class="badge text-bg-light border"><%= H(Businesses_Label(Businesses_Outcomes(), it("outcome"))) %></span><% End If %>
  110. <% If Not IsNull(it("follow_up_date")) Then %><span class="small text-muted"><i class="bi bi-arrow-return-right"></i> again on <%= Date_Fmt(it("follow_up_date")) %></span><% End If %>
  111. </div>
  112. <% If Len(it("notes") & "") > 0 Then %><div class="mt-1"><%= Html_Nl2Br(it("notes")) %></div><% End If %>
  113. </li>
  114. <% Next %>
  115. </ul>
  116. <% End If %>
  117. </div>
  118. </div>
  119. </div>
  120. <!-- RIGHT: details -->
  121. <div class="col-lg-5">
  122. <div class="card shadow-sm mb-3">
  123. <div class="card-body">
  124. <h2 class="h5 mb-3">Details</h2>
  125. <div class="mb-3 small">
  126. <% If Len(b("phone") & "") > 0 Then %><div><i class="bi bi-telephone"></i> <a href="tel:<%= H(b("phone")) %>"><%= H(b("phone")) %></a></div><% End If %>
  127. <% If Len(b("email") & "") > 0 Then %><div><i class="bi bi-envelope"></i> <a href="mailto:<%= H(b("email")) %>"><%= H(b("email")) %></a></div><% End If %>
  128. <% If Len(b("website") & "") > 0 Then %><div><i class="bi bi-globe"></i> <a href="<% If LCase(Left(b("website"), 4)) = "http" Then Response.Write H(b("website")) Else Response.Write "https://" & H(b("website")) %>" target="_blank" rel="noopener noreferrer"><%= H(b("website")) %></a></div><% End If %>
  129. <% If Len(b("address1") & "") > 0 Or Len(b("city") & "") > 0 Then %><div><i class="bi bi-geo-alt"></i> <%= H(b("address1")) %><% If Len(b("address1") & "") > 0 And Len(b("city") & "") > 0 Then Response.Write ", " %><%= H(b("city")) %><% If Len(b("state") & "") > 0 Then Response.Write ", " & H(b("state")) %>&nbsp;<%= H(b("zip")) %></div><% End If %>
  130. </div>
  131. <% If Not dup Is Nothing Then %>
  132. <div class="alert alert-warning small">
  133. <i class="bi bi-exclamation-triangle"></i>
  134. Nothing was saved yet. The <%= dup("matched") %> you entered is already used by
  135. <a href="/businesses/<%= dup("id") %>" target="_blank" rel="noopener"><%= H(dup("name")) %></a>.
  136. Fix it, or press <strong>Save anyway</strong> to keep both.
  137. </div>
  138. <% End If %>
  139. <form method="post" action="/businesses/<%= bid %>/update">
  140. <input type="hidden" name="csrf" value="<%= H(csrf) %>" />
  141. <% If Not dup Is Nothing Then %><input type="hidden" name="allow_duplicate" value="1" /><% End If %>
  142. <div class="mb-2">
  143. <label class="form-label small mb-1" for="f_name">Business name</label>
  144. <input type="text" class="form-control form-control-sm" id="f_name" name="name" value="<%= H(fv("name")) %>" maxlength="255" required />
  145. </div>
  146. <div class="mb-2">
  147. <label class="form-label small mb-1" for="f_contact">Contact</label>
  148. <input type="text" class="form-control form-control-sm" id="f_contact" name="contact_name" value="<%= H(fv("contact_name")) %>" maxlength="150" />
  149. </div>
  150. <div class="row g-2 mb-2">
  151. <div class="col-6">
  152. <label class="form-label small mb-1" for="f_phone">Phone</label>
  153. <input type="text" class="form-control form-control-sm" id="f_phone" name="phone" value="<%= H(fv("phone")) %>" maxlength="40" />
  154. </div>
  155. <div class="col-6">
  156. <label class="form-label small mb-1" for="f_email">Email</label>
  157. <input type="text" class="form-control form-control-sm" id="f_email" name="email" value="<%= H(fv("email")) %>" maxlength="255" />
  158. </div>
  159. </div>
  160. <div class="mb-2">
  161. <label class="form-label small mb-1" for="f_web">Website</label>
  162. <input type="text" class="form-control form-control-sm" id="f_web" name="website" value="<%= H(fv("website")) %>" maxlength="255" />
  163. </div>
  164. <div class="mb-2">
  165. <label class="form-label small mb-1" for="f_addr">Address</label>
  166. <input type="text" class="form-control form-control-sm" id="f_addr" name="address1" value="<%= H(fv("address1")) %>" maxlength="255" />
  167. </div>
  168. <div class="row g-2 mb-2">
  169. <div class="col-5"><label class="form-label small mb-1" for="f_city">City</label><input type="text" class="form-control form-control-sm" id="f_city" name="city" value="<%= H(fv("city")) %>" maxlength="100" /></div>
  170. <div class="col-3"><label class="form-label small mb-1" for="f_state">State</label><input type="text" class="form-control form-control-sm" id="f_state" name="state" value="<%= H(fv("state")) %>" maxlength="50" /></div>
  171. <div class="col-4"><label class="form-label small mb-1" for="f_zip">Zip</label><input type="text" class="form-control form-control-sm" id="f_zip" name="zip" value="<%= H(fv("zip")) %>" maxlength="20" /></div>
  172. </div>
  173. <div class="row g-2 mb-2">
  174. <div class="col-6">
  175. <label class="form-label small mb-1" for="f_ind">Industry</label>
  176. <select class="form-select form-select-sm" id="f_ind" name="industry_id">
  177. <option value="">(none)</option>
  178. <% For Each indKey2 In industries.Keys %>
  179. <option value="<%= indKey2 %>"<% If CStr(fv("industry_id") & "") = indKey2 Then Response.Write " selected" %>><%= H(industries(indKey2)) %></option>
  180. <% Next %>
  181. </select>
  182. </div>
  183. <div class="col-6">
  184. <label class="form-label small mb-1" for="f_indnew">&hellip;or add new</label>
  185. <input type="text" class="form-control form-control-sm" id="f_indnew" name="industry_new" maxlength="100" value="<% If fv.Exists("_industry_new") Then Response.Write H(fv("_industry_new")) %>" />
  186. </div>
  187. </div>
  188. <fieldset class="mb-2">
  189. <legend class="form-label small mb-1">Areas served</legend>
  190. <% If allAreas.Count > 0 Then %>
  191. <div class="border rounded px-2 py-1 mb-1" style="max-height:9rem;overflow-y:auto">
  192. <% For ix = 0 To allAreas.Count - 1 %>
  193. <div class="form-check form-check-inline">
  194. <input class="form-check-input" type="checkbox" id="f_area_<%= allAreas(ix)("id") %>" name="area_ids" value="<%= allAreas(ix)("id") %>"<% If areaSel.Exists(CStr(allAreas(ix)("id"))) Then Response.Write " checked" %> />
  195. <label class="form-check-label small" for="f_area_<%= allAreas(ix)("id") %>"><%= H(allAreas(ix)("name")) %></label>
  196. </div>
  197. <% Next %>
  198. </div>
  199. <% End If %>
  200. <label class="visually-hidden" for="f_areanew">Add new areas</label>
  201. <input type="text" class="form-control form-control-sm" id="f_areanew" name="area_new" maxlength="500" placeholder="<% If allAreas.Count > 0 Then Response.Write "&hellip;or add new, comma-separated" Else Response.Write "e.g. Dallas, Fort Worth" %>" value="<% If fv.Exists("_area_new") Then Response.Write H(fv("_area_new")) %>" />
  202. </fieldset>
  203. <div class="row g-2 mb-2 align-items-end">
  204. <div class="col-6">
  205. <div class="form-check">
  206. <input class="form-check-input" type="checkbox" id="f_cust" name="is_customer" value="1"<% If fv("is_customer") & "" = "1" Then Response.Write " checked" %> />
  207. <label class="form-check-label small" for="f_cust">Previous customer</label>
  208. </div>
  209. </div>
  210. <div class="col-6">
  211. <label class="form-label small mb-1" for="f_first">First order</label>
  212. <input type="date" class="form-control form-control-sm" id="f_first" name="first_order_date" value="<%= Date_Iso(fv("first_order_date")) %>" />
  213. </div>
  214. </div>
  215. <div class="mb-3">
  216. <label class="form-label small mb-1" for="f_notes">Notes <span class="text-muted">(other people, anything else)</span></label>
  217. <textarea class="form-control form-control-sm" id="f_notes" name="notes" rows="4" maxlength="10000"><%= H(fv("notes")) %></textarea>
  218. </div>
  219. <button type="submit" class="btn <% If dup Is Nothing Then Response.Write "btn-outline-primary" Else Response.Write "btn-warning" %> btn-sm"><% If dup Is Nothing Then Response.Write "Save details" Else Response.Write "Save anyway" %></button>
  220. </form>
  221. </div>
  222. </div>
  223. <% If Not isRemoved Then %>
  224. <div class="card border-danger-subtle shadow-sm mb-3">
  225. <div class="card-body">
  226. <h2 class="h6 text-danger">Remove from list</h2>
  227. <form method="post" action="/businesses/<%= bid %>/remove" class="d-flex gap-2">
  228. <input type="hidden" name="csrf" value="<%= H(csrf) %>" />
  229. <input type="text" class="form-control form-control-sm" name="reason" placeholder="Reason (optional)" maxlength="255" />
  230. <button type="submit" class="btn btn-outline-danger btn-sm text-nowrap">Remove</button>
  231. </form>
  232. <div class="form-text">Removed businesses are hidden from the list and won't be re-added by an import. You can restore them.</div>
  233. </div>
  234. </div>
  235. <% End If %>
  236. <p class="text-muted small">
  237. Added <%= Date_Fmt(b("created_at")) %><% If Not IsNull(b("import_batch_id")) Then Response.Write " &middot; import batch #" & b("import_batch_id") %>
  238. <% If Len(b("source") & "") > 0 Then %>&middot; <%= H(b("source")) %><% End If %>
  239. </p>
  240. </div>
  241. </div>
  242. <script>
  243. (function () {
  244. var fu = document.getElementById('follow_up_date');
  245. document.querySelectorAll('[data-days]').forEach(function (btn) {
  246. btn.addEventListener('click', function () {
  247. var n = parseInt(btn.getAttribute('data-days'), 10);
  248. if (!fu) return;
  249. if (n === 0) { fu.value = ''; return; }
  250. var d = new Date(); d.setDate(d.getDate() + n);
  251. var m = ('0' + (d.getMonth() + 1)).slice(-2), day = ('0' + d.getDate()).slice(-2);
  252. fu.value = d.getFullYear() + '-' + m + '-' + day;
  253. });
  254. });
  255. var oc = document.getElementById('outcome'), hint = document.getElementById('removeHint');
  256. if (oc && hint) oc.addEventListener('change', function () { hint.hidden = (oc.value !== 'remove'); });
  257. })();
  258. </script>

Powered by TurnKey Linux.