No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 

235 líneas
11 KiB

  1. {# templates/client/index.html.twig #}
  2. {% extends 'base.html.twig' %}
  3. {% block title %}{{ 'app.client.page_title'|trans }}{% endblock %}
  4. {% block body %}
  5. <script>
  6. window.CRUD = {
  7. apiBase: '/api/clients',
  8. clients: null,
  9. hasLexofficeApiKey: {{ hasLexofficeApiKey ? 'true' : 'false' }},
  10. i18n: {
  11. confirmDelete: {{ 'app.crud.confirm_delete'|trans|json_encode|raw }},
  12. confirmArchive: {{ 'app.crud.confirm_archive'|trans|json_encode|raw }},
  13. errorSave: {{ 'app.crud.error_save'|trans|json_encode|raw }},
  14. errorDelete: {{ 'app.crud.error_delete'|trans|json_encode|raw }},
  15. errorArchive: {{ 'app.crud.error_archive'|trans|json_encode|raw }},
  16. errorRestore: {{ 'app.crud.error_restore'|trans|json_encode|raw }},
  17. errorNoName: {{ 'app.crud.error_no_name'|trans|json_encode|raw }},
  18. selectPh: {{ 'app.crud.select_ph'|trans|json_encode|raw }},
  19. labelName: {{ 'app.crud.label_name'|trans|json_encode|raw }},
  20. labelRate: {{ 'app.crud.label_rate'|trans|json_encode|raw }},
  21. labelNote: {{ 'app.crud.label_note'|trans|json_encode|raw }},
  22. labelClient: {{ 'app.crud.label_client'|trans|json_encode|raw }},
  23. labelBillable: {{ 'app.service.label_billable'|trans|json_encode|raw }},
  24. billableLabel: {{ 'app.service.billable_checkbox'|trans|json_encode|raw }},
  25. btnSave: {{ 'app.entry.btn_save'|trans|json_encode|raw }},
  26. btnCancel: {{ 'app.entry.btn_cancel'|trans|json_encode|raw }},
  27. btnEdit: {{ 'app.entry.btn_edit'|trans|json_encode|raw }},
  28. btnDelete: {{ 'app.entry.btn_delete'|trans|json_encode|raw }},
  29. btnRestore: {{ 'app.crud.btn_restore'|trans|json_encode|raw }},
  30. groupBillable: {{ 'app.service.billable'|trans|json_encode|raw }},
  31. groupNotBillable: {{ 'app.service.not_billable'|trans|json_encode|raw }},
  32. projectSingular: {{ 'app.crud.project_singular'|trans|json_encode|raw }},
  33. projectPlural: {{ 'app.crud.project_plural'|trans|json_encode|raw }},
  34. rateModeDefault: {{ 'app.crud.rate_mode_default'|trans|json_encode|raw }},
  35. rateModeCustom: {{ 'app.crud.rate_mode_custom'|trans|json_encode|raw }},
  36. lexofficeCheckbox: {{ 'app.lexoffice.checkbox_label'|trans|json_encode|raw }},
  37. lexofficeSelect: {{ 'app.lexoffice.select_contact'|trans|json_encode|raw }},
  38. lexofficeSearch: {{ 'app.lexoffice.search'|trans|json_encode|raw }},
  39. lexofficeReload: {{ 'app.lexoffice.reload'|trans|json_encode|raw }},
  40. lexofficeLoading: {{ 'app.lexoffice.loading'|trans|json_encode|raw }},
  41. lexofficeErrorLoad: {{ 'app.lexoffice.error_load_contacts'|trans|json_encode|raw }},
  42. lexofficeRefreshed: {{ 'app.lexoffice.refreshed'|trans|json_encode|raw }},
  43. lexofficeErrorApi: {{ 'app.lexoffice.error_api'|trans|json_encode|raw }},
  44. },
  45. };
  46. </script>
  47. <div class="crud-page">
  48. <div class="crud-page__header">
  49. <h1 class="crud-page__title">{{ 'app.client.page_title'|trans }}</h1>
  50. <button class="btn btn-primary" id="btn-new">{{ 'app.client.btn_new'|trans }}</button>
  51. </div>
  52. <div class="crud-create" id="crud-create">
  53. <div class="entry-form__grid">
  54. {% if hasLexofficeApiKey %}
  55. <label class="entry-form__label">&nbsp;</label>
  56. <div class="entry-form__field">
  57. <label class="crud-checkbox-label">
  58. <input type="checkbox" id="create-lexoffice" />
  59. <span>{{ 'app.lexoffice.checkbox_label'|trans }}</span>
  60. </label>
  61. </div>
  62. {% endif %}
  63. {% if hasLexofficeApiKey %}
  64. <label class="entry-form__label" id="create-lexoffice-select-label" hidden>{{ 'app.lexoffice.select_contact'|trans }}</label>
  65. <div class="entry-form__field" id="create-lexoffice-select-field" hidden>
  66. <div class="lexoffice-select-wrap" id="create-lexoffice-select"
  67. data-placeholder="{{ 'app.lexoffice.select_contact'|trans }}"></div>
  68. </div>
  69. {% endif %}
  70. <label class="entry-form__label">{{ 'app.crud.label_name'|trans }}</label>
  71. <div class="entry-form__field">
  72. <input type="text" id="create-name" class="input" placeholder="{{ 'app.client.placeholder_name'|trans }}" />
  73. </div>
  74. <label class="entry-form__label">{{ 'app.crud.label_rate'|trans }}</label>
  75. <div class="entry-form__field">
  76. <div class="rate-mode">
  77. <label class="rate-mode__option">
  78. <input type="radio" name="create-rate-mode" value="default" checked />
  79. <span>{{ 'app.crud.rate_mode_default'|trans }}</span>
  80. </label>
  81. <label class="rate-mode__option">
  82. <input type="radio" name="create-rate-mode" value="custom" />
  83. <span>{{ 'app.crud.rate_mode_custom'|trans }}</span>
  84. </label>
  85. <div class="rate-mode__input" hidden>
  86. <input type="number" id="create-rate" class="input input--rate" placeholder="0,00" step="0.01" min="0" />
  87. <span class="entry-form__unit">&euro;</span>
  88. </div>
  89. </div>
  90. </div>
  91. <label class="entry-form__label">{{ 'app.crud.label_note'|trans }}</label>
  92. <div class="entry-form__field">
  93. <textarea id="create-note" class="textarea" rows="2"></textarea>
  94. </div>
  95. <div class="entry-form__actions">
  96. <button type="button" class="btn btn-primary" id="btn-create-save">{{ 'app.entry.btn_create'|trans }}</button>
  97. <button type="button" class="btn btn-secondary" id="btn-create-cancel">{{ 'app.entry.btn_cancel'|trans }}</button>
  98. </div>
  99. </div>
  100. </div>
  101. <div class="crud-tabs">
  102. <button class="crud-tab crud-tab--active" data-tab="active">{{ 'app.crud.tab_active'|trans }}</button>
  103. <button class="crud-tab" data-tab="archived">{{ 'app.crud.tab_archived'|trans }}</button>
  104. </div>
  105. <div class="crud-list" id="crud-list">
  106. {% for client in clients %}
  107. <div class="crud-row{% if client.isArchived() %} crud-row--archived{% endif %}"
  108. id="client-{{ client.id }}"
  109. data-id="{{ client.id }}"
  110. data-archived="{{ client.isArchived() ? '1' : '0' }}"
  111. data-name="{{ client.name|e('html_attr') }}"
  112. data-rate="{{ client.hourlyRate|default('') }}"
  113. data-note="{{ client.note|default('')|e('html_attr') }}"
  114. data-lexoffice-contact-id="{{ client.lexofficeContactId|default('') }}">
  115. <div class="crud-row__display">
  116. <div class="crud-row__info">
  117. <span class="crud-row__name">{{ client.name }}</span>
  118. <span class="crud-row__meta">
  119. {% set count = client.projects|length %}
  120. {{ count }} {{ count == 1 ? 'app.crud.project_singular'|trans : 'app.crud.project_plural'|trans }}
  121. </span>
  122. </div>
  123. <div class="crud-row__actions">
  124. {% if client.isArchived() %}
  125. <button class="crud-row__btn crud-row__btn--restore" data-action="unarchive" title="{{ 'app.crud.btn_restore'|trans }}">
  126. {% include '_atoms/icon-restore.html.twig' %}
  127. </button>
  128. {% else %}
  129. <button class="crud-row__btn crud-row__btn--edit" data-action="edit" title="{{ 'app.entry.btn_edit'|trans }}">
  130. {% include '_atoms/icon-edit.html.twig' %}
  131. </button>
  132. <button class="crud-row__btn crud-row__btn--delete" data-action="delete" title="{{ 'app.entry.btn_delete'|trans }}">
  133. {% include '_atoms/icon-delete.html.twig' %}
  134. </button>
  135. {% endif %}
  136. </div>
  137. </div>
  138. {% if not client.isArchived() %}
  139. <div class="crud-row__edit" hidden>
  140. <div class="entry-form__grid entry-form__grid--inline">
  141. {% if hasLexofficeApiKey %}
  142. <label class="entry-form__label">&nbsp;</label>
  143. <div class="entry-form__field">
  144. <label class="crud-checkbox-label">
  145. <input type="checkbox" class="edit-lexoffice" {{ client.isLexofficeClient() ? 'checked' : '' }} />
  146. <span>{{ 'app.lexoffice.checkbox_label'|trans }}</span>
  147. </label>
  148. </div>
  149. <label class="entry-form__label edit-lexoffice-select-label"
  150. {{ not client.isLexofficeClient() ? 'hidden' : '' }}>{{ 'app.lexoffice.select_contact'|trans }}</label>
  151. <div class="entry-form__field edit-lexoffice-select-field"
  152. {{ not client.isLexofficeClient() ? 'hidden' : '' }}>
  153. <div class="lexoffice-select-wrap edit-lexoffice-select"
  154. data-placeholder="{{ 'app.lexoffice.select_contact'|trans }}"
  155. data-contact-id="{{ client.lexofficeContactId|default('') }}"></div>
  156. </div>
  157. {% endif %}
  158. <label class="entry-form__label">{{ 'app.crud.label_name'|trans }}</label>
  159. <div class="entry-form__field">
  160. <input type="text" class="input edit-name" value="{{ client.name }}"
  161. {{ client.isLexofficeClient() ? 'disabled' : '' }} />
  162. </div>
  163. <label class="entry-form__label">{{ 'app.crud.label_rate'|trans }}</label>
  164. <div class="entry-form__field">
  165. <div class="rate-mode">
  166. <label class="rate-mode__option">
  167. <input type="radio" name="edit-rate-mode-{{ client.id }}" value="default"
  168. {{ client.hourlyRate is null ? 'checked' : '' }} />
  169. <span>{{ 'app.crud.rate_mode_default'|trans }}</span>
  170. </label>
  171. <label class="rate-mode__option">
  172. <input type="radio" name="edit-rate-mode-{{ client.id }}" value="custom"
  173. {{ client.hourlyRate is not null ? 'checked' : '' }} />
  174. <span>{{ 'app.crud.rate_mode_custom'|trans }}</span>
  175. </label>
  176. <div class="rate-mode__input"{{ client.hourlyRate is null ? ' hidden' : '' }}>
  177. <input type="number" class="input input--rate edit-rate"
  178. value="{{ client.hourlyRate|default('') }}" step="0.01" min="0" />
  179. <span class="entry-form__unit">&euro;</span>
  180. </div>
  181. </div>
  182. </div>
  183. <label class="entry-form__label">{{ 'app.crud.label_note'|trans }}</label>
  184. <div class="entry-form__field">
  185. <textarea class="textarea edit-note" rows="2">{{ client.note|default('') }}</textarea>
  186. </div>
  187. <div class="entry-form__actions">
  188. <button type="button" class="btn btn-primary" data-action="save">{{ 'app.entry.btn_save'|trans }}</button>
  189. <button type="button" class="btn btn-secondary" data-action="cancel">{{ 'app.entry.btn_cancel'|trans }}</button>
  190. </div>
  191. </div>
  192. </div>
  193. {% endif %}
  194. </div>
  195. {% else %}
  196. <div class="empty-state">
  197. <p class="empty-state__title">{{ 'app.client.empty'|trans }}</p>
  198. </div>
  199. {% endfor %}
  200. </div>
  201. </div>
  202. {% endblock %}
  203. {% block javascripts %}
  204. {{ parent() }}
  205. {{ encore_entry_script_tags('crud') }}
  206. {% endblock %}