|
- {# templates/team/index.html.twig #}
- {% extends 'base.html.twig' %}
-
- {% block title %}{{ 'app.team.page_title'|trans }}{% endblock %}
-
- {% block body %}
- <script>
- window.Team = {
- i18n: {
- confirmDelete: {{ 'app.team.confirm_delete'|trans|json_encode|raw }},
- confirmArchive: {{ 'app.team.confirm_archive'|trans|json_encode|raw }},
- confirmRevokeInvite:{{ 'app.team.confirm_revoke_invite'|trans|json_encode|raw }},
- errorSave: {{ 'app.team.error_save'|trans|json_encode|raw }},
- errorDelete: {{ 'app.team.error_delete'|trans|json_encode|raw }},
- errorArchive: {{ 'app.team.error_archive'|trans|json_encode|raw }},
- errorRestore: {{ 'app.team.error_restore'|trans|json_encode|raw }},
- errorGeneric: {{ 'app.team.error_generic'|trans|json_encode|raw }},
- }
- };
- </script>
- <div class="crud-page">
-
- <div class="crud-page__header">
- <h1 class="crud-page__title">{{ 'app.team.page_title'|trans }}</h1>
- <button class="btn btn-primary" id="team-invite-btn">{{ 'app.team.btn_new'|trans }}</button>
- </div>
-
- <div class="crud-tabs">
- <button class="crud-tab crud-tab--active" data-tab="active">
- {{ 'app.crud.tab_active'|trans }} ({{ activeUsers|length + pendingInvites|length }})
- </button>
- <button class="crud-tab" data-tab="archived">
- {{ 'app.crud.tab_archived'|trans }} ({{ archivedUsers|length }})
- </button>
- </div>
-
- {# ── Aktive User ──────────────────────────────────────────────────── #}
- <div class="crud-list" id="team-list" data-tab-panel="active">
-
- {% for au in activeUsers %}
- <div class="crud-row"
- id="au-{{ au.id }}"
- data-id="{{ au.id }}"
- data-first-name="{{ au.user.firstName|e('html_attr') }}"
- data-last-name="{{ au.user.lastName|e('html_attr') }}"
- data-email="{{ au.user.email|e('html_attr') }}"
- data-note="{{ au.user.note|default('')|e('html_attr') }}"
- data-role="{{ au.role }}"
- data-is-self="{{ au.user.id == currentUserId ? '1' : '0' }}">
-
- <div class="crud-row__display">
- <div class="crud-row__info">
- <span class="crud-row__name">{{ au.user.fullName }}</span>
- <span class="crud-row__meta">({{ au.roleLabelKey|trans }})</span>
- {% if au.user.password is null %}
- <span class="team-badge team-badge--pending">{{ 'app.team.invite_pending'|trans }}</span>
- {% endif %}
- </div>
- <div class="crud-row__actions">
- <button class="crud-row__btn crud-row__btn--edit"
- data-action="edit"
- title="{{ 'app.entry.btn_edit'|trans }}">
- {% include '_atoms/icon-edit.html.twig' %}
- </button>
- {% if au.user.id != currentUserId %}
- <button class="crud-row__btn crud-row__btn--delete"
- data-action="delete"
- title="{{ 'app.team.btn_remove'|trans }}">
- {% include '_atoms/icon-delete.html.twig' %}
- </button>
- {% endif %}
- </div>
- </div>
-
- <div class="crud-row__edit" hidden>
- <div class="entry-form__grid entry-form__grid--inline">
-
- <label class="entry-form__label">{{ 'app.team.label_first_name'|trans }}</label>
- <div class="entry-form__field">
- <input type="text" class="input edit-first-name"
- value="{{ au.user.firstName }}" />
- </div>
-
- <label class="entry-form__label">{{ 'app.team.label_last_name'|trans }}</label>
- <div class="entry-form__field">
- <input type="text" class="input edit-last-name"
- value="{{ au.user.lastName }}" />
- </div>
-
- <label class="entry-form__label">{{ 'app.team.label_email'|trans }}</label>
- <div class="entry-form__field">
- <input type="email" class="input edit-email"
- value="{{ au.user.email }}" />
- </div>
-
- <label class="entry-form__label">{{ 'app.crud.label_note'|trans }}</label>
- <div class="entry-form__field">
- <textarea class="textarea edit-note" rows="2">{{ au.user.note|default('') }}</textarea>
- </div>
-
- <label class="entry-form__label">{{ 'app.team.label_role'|trans }}</label>
- <div class="entry-form__field">
- <div class="team-role-selector{% if au.user.id == currentUserId and au.isAdmin() %} team-role-selector--disabled{% endif %}">
- {% set roleDisabled = (au.user.id == currentUserId and au.isAdmin()) ? 'disabled' : '' %}
- <label class="team-role-option">
- <input type="radio" class="edit-role" name="role-{{ au.id }}"
- value="tracker" {{ au.role == 'tracker' ? 'checked' : '' }} {{ roleDisabled }} />
- <span class="team-role-option__label">{{ 'app.team.role_tracker'|trans }}</span>
- </label>
- <label class="team-role-option">
- <input type="radio" class="edit-role" name="role-{{ au.id }}"
- value="member" {{ au.role == 'member' ? 'checked' : '' }} {{ roleDisabled }} />
- <span class="team-role-option__label">{{ 'app.team.role_member'|trans }}</span>
- </label>
- <label class="team-role-option">
- <input type="radio" class="edit-role" name="role-{{ au.id }}"
- value="admin" {{ au.role == 'admin' ? 'checked' : '' }} {{ roleDisabled }} />
- <span class="team-role-option__label">{{ 'app.team.role_admin'|trans }}</span>
- </label>
- </div>
- {% if au.user.id == currentUserId and au.isAdmin() %}
- <p class="team-role-hint">{{ 'app.team.role_change_disabled'|trans }}</p>
- {% endif %}
- </div>
-
- <div class="entry-form__actions">
- <button type="button" class="btn btn-primary" data-action="save">{{ 'app.entry.btn_save'|trans }}</button>
- <button type="button" class="btn btn-secondary" data-action="cancel">{{ 'app.entry.btn_cancel'|trans }}</button>
- </div>
-
- </div>
- </div>
-
- </div>
- {% endfor %}
-
- {# ── Ausstehende Einladungen ──────────────────────────────────── #}
- {% for invite in pendingInvites %}
- <div class="crud-row" id="invite-{{ invite.id }}">
- <div class="crud-row__display">
- <div class="crud-row__info">
- <span class="crud-row__name">{{ invite.firstName }} {{ invite.lastName }}</span>
- <span class="crud-row__meta">({{ invite.email }})</span>
- <span class="team-badge team-badge--pending">{{ 'app.team.invite_pending'|trans }}</span>
- </div>
- <div class="crud-row__actions">
- <button class="crud-row__btn crud-row__btn--delete"
- data-action="delete-invite"
- data-id="{{ invite.id }}"
- title="{{ 'app.team.btn_revoke_invite'|trans }}">
- {% include '_atoms/icon-delete.html.twig' %}
- </button>
- </div>
- </div>
- </div>
- {% endfor %}
-
- {% if activeUsers is empty and pendingInvites is empty %}
- <div class="crud-list__empty">{{ 'app.team.empty_active'|trans }}</div>
- {% endif %}
-
- </div>
-
- {# ── Archivierte User ─────────────────────────────────────────────── #}
- <div class="crud-list" id="team-list-archived" data-tab-panel="archived" hidden>
-
- {% for au in archivedUsers %}
- <div class="crud-row crud-row--archived" id="au-{{ au.id }}" data-id="{{ au.id }}">
- <div class="crud-row__display">
- <div class="crud-row__info">
- <span class="crud-row__name">{{ au.user.fullName }}</span>
- <span class="crud-row__meta">({{ au.roleLabelKey|trans }})</span>
- </div>
- <div class="crud-row__actions">
- <button class="crud-row__btn crud-row__btn--restore"
- data-action="unarchive"
- title="{{ 'app.crud.btn_restore'|trans }}">
- {% include '_atoms/icon-restore.html.twig' %}
- </button>
- </div>
- </div>
- </div>
- {% else %}
- <div class="crud-list__empty">{{ 'app.team.empty_archived'|trans }}</div>
- {% endfor %}
-
- </div>
-
- </div>
-
- {# ── Einlade-Modal ────────────────────────────────────────────────────────────── #}
- <div class="modal-overlay" id="team-modal" hidden>
- <div class="modal-card">
- <div class="modal-card__header">
- <h2 class="modal-card__title">{{ 'app.team.modal_title'|trans }}</h2>
- <button class="modal-card__close" id="team-modal-close" type="button">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
- </svg>
- </button>
- </div>
-
- <div id="team-modal-errors" class="form-errors" hidden></div>
-
- <div class="modal-card__body">
- <div class="form-row">
- <div class="form-field">
- <label class="form-field__label" for="inv-firstName">{{ 'app.team.label_first_name'|trans }}</label>
- <input class="input" type="text" id="inv-firstName" autocomplete="off" />
- </div>
- <div class="form-field">
- <label class="form-field__label" for="inv-lastName">{{ 'app.team.label_last_name'|trans }}</label>
- <input class="input" type="text" id="inv-lastName" autocomplete="off" />
- </div>
- </div>
- <div class="form-field">
- <label class="form-field__label" for="inv-email">{{ 'app.team.label_email'|trans }}</label>
- <input class="input" type="email" id="inv-email" autocomplete="off" />
- </div>
- <div class="form-field">
- <label class="form-field__label">{{ 'app.team.label_role'|trans }}</label>
- <div class="team-role-selector">
- <label class="team-role-option">
- <input type="radio" name="inv-role" value="tracker" />
- <span class="team-role-option__label">{{ 'app.team.role_tracker'|trans }}</span>
- </label>
- <label class="team-role-option">
- <input type="radio" name="inv-role" value="member" checked />
- <span class="team-role-option__label">{{ 'app.team.role_member'|trans }}</span>
- </label>
- <label class="team-role-option">
- <input type="radio" name="inv-role" value="admin" />
- <span class="team-role-option__label">{{ 'app.team.role_admin'|trans }}</span>
- </label>
- </div>
- </div>
- </div>
-
- <div class="modal-card__footer">
- <button class="btn btn-secondary" id="team-modal-cancel" type="button">{{ 'app.entry.btn_cancel'|trans }}</button>
- <button class="btn btn-cta" id="team-modal-submit" type="button">{{ 'app.team.btn_invite'|trans }}</button>
- </div>
- </div>
- </div>
-
- {% endblock %}
-
- {% block javascripts %}
- {{ parent() }}
- {{ encore_entry_script_tags('team') }}
- {% endblock %}
|