Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/TEMPLATES/repricer_team.html
Diff
/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/TEMPLATES/repricer_team.html
added on local at 2026-07-01 21:47:27
Added
+237
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 5b2860402fac
to 5b2860402fac
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.| 1 | <div class="page-head"> | |
| 2 | <div> | |
| 3 | <span class="page-eyebrow"><span class="dot"></span> Account & preferences</span> | |
| 4 | <h1 class="page-title">Team Members</h1> | |
| 5 | <p class="page-subtitle">Add teammates who can sign in and help run your store. Their access is scoped by the role you pick — private billing details stay yours alone.</p> | |
| 6 | </div> | |
| 7 | </div> | |
| 8 | ||
| 9 | [if:$has_flash] | |
| 10 | <div class="banner [if:$flash_is_success]success[/if][if:$flash_is_error]error[/if] mb-3"> | |
| 11 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/></svg> | |
| 12 | <div class="text-sm fw-600">$flash_msg</div> | |
| 13 | </div> | |
| 14 | [/if] | |
| 15 | ||
| 16 | [if:!$has_perm_ready] | |
| 17 | <div class="banner warn mb-3"> | |
| 18 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/></svg> | |
| 19 | <div class="text-sm fw-600">Permission tables not installed yet — run the DB migration to enable team management.</div> | |
| 20 | </div> | |
| 21 | [/if] | |
| 22 | ||
| 23 | [if:$has_perm_ready] | |
| 24 | <div class="module"> | |
| 25 | <div class="module-head"> | |
| 26 | <div class="left"> | |
| 27 | <div class="module-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></div> | |
| 28 | <div> | |
| 29 | <div class="module-title">Your team ($member_count)</div> | |
| 30 | <div class="module-sub">Owner: $owner_display</div> | |
| 31 | </div> | |
| 32 | </div> | |
| 33 | </div> | |
| 34 | ||
| 35 | [if:$has_members] | |
| 36 | <div class="table-wrap" style="border:none;border-radius:0"> | |
| 37 | <table class="table"> | |
| 38 | <thead> | |
| 39 | <tr> | |
| 40 | <th>Member</th> | |
| 41 | <th>Role</th> | |
| 42 | <th class="num">Added</th> | |
| 43 | <th class="num">Last seen</th> | |
| 44 | <th></th> | |
| 45 | </tr> | |
| 46 | </thead> | |
| 47 | <tbody> | |
| 48 | [loop:@members] | |
| 49 | <tr> | |
| 50 | <td> | |
| 51 | <div class="fw-600" style="color:#fff">$loop1.display_name</div> | |
| 52 | <div class="text-xs text-dim">$loop1.email</div> | |
| 53 | </td> | |
| 54 | <td> | |
| 55 | <form method="post" action="/team.cgi" style="display:flex;gap:6px;align-items:center;margin:0"> | |
| 56 | <input type="hidden" name="action" value="update_role"> | |
| 57 | <input type="hidden" name="member_id" value="$loop1.id"> | |
| 58 | <select class="select" name="permission_groups_id" style="min-width:140px"> | |
| 59 | [loop:@role_options]<option value="$loop2.value"$loop2.selected_attr>$loop2.label</option>[/loop] | |
| 60 | </select> | |
| 61 | <button type="submit" class="btn btn-secondary btn-sm">Save</button> | |
| 62 | </form> | |
| 63 | </td> | |
| 64 | <td class="num text-dim">$loop1.added_on</td> | |
| 65 | <td class="num text-dim">$loop1.last_seen</td> | |
| 66 | <td> | |
| 67 | <form method="post" action="/team.cgi" | |
| 68 | data-confirm-title="Remove this team member?" | |
| 69 | data-confirm-message="They will lose access to your store immediately." | |
| 70 | data-confirm-label="Remove member" | |
| 71 | data-confirm-style="danger" | |
| 72 | style="margin:0"> | |
| 73 | <input type="hidden" name="action" value="remove_member"> | |
| 74 | <input type="hidden" name="member_id" value="$loop1.id"> | |
| 75 | <button type="submit" class="text-danger text-xs fw-600" style="background:none;border:0;padding:0;cursor:pointer">Remove</button> | |
| 76 | </form> | |
| 77 | </td> | |
| 78 | </tr> | |
| 79 | [/loop] | |
| 80 | </tbody> | |
| 81 | </table> | |
| 82 | </div> | |
| 83 | [/if] | |
| 84 | [if:!$has_members] | |
| 85 | <div class="module-body" style="text-align:center;padding:32px 20px"> | |
| 86 | <div class="text-sm fw-600" style="color:#fff;margin-bottom:6px">You're the only member</div> | |
| 87 | <div class="text-xs text-dim">Add a teammate below to share day-to-day store work.</div> | |
| 88 | </div> | |
| 89 | [/if] | |
| 90 | </div> | |
| 91 | ||
| 92 | [if:$has_role_cards] | |
| 93 | <div class="module mt-3"> | |
| 94 | <div class="module-head"> | |
| 95 | <div class="left"> | |
| 96 | <div class="module-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 12l2 2 4-4"/><circle cx="12" cy="12" r="10"/></svg></div> | |
| 97 | <div> | |
| 98 | <div class="module-title">Roles</div> | |
| 99 | <div class="module-sub">Built-in presets (Manager / Editor / Viewer) cover most teams; create custom roles below if you need a narrower or wider grant. Billing, team management, account deletion, and destructive ops (delete models, refund orders) stay owner-only no matter what.</div> | |
| 100 | </div> | |
| 101 | </div> | |
| 102 | </div> | |
| 103 | <div class="module-body"> | |
| 104 | <div class="dash-grid-3" style="gap:12px"> | |
| 105 | [loop:@role_cards] | |
| 106 | <div style="border:1px solid var(--border);border-radius:8px;padding:14px;background:rgba(255,255,255,0.02);display:flex;flex-direction:column;gap:8px"> | |
| 107 | <div style="display:flex;align-items:center;justify-content:space-between;gap:8px"> | |
| 108 | <div class="fw-600" style="color:#fff">$loop1.name</div> | |
| 109 | [if:$loop1.is_preset]<span class="pill" style="font-size:9.5px;letter-spacing:1px;padding:2px 7px;background:rgba(148,163,184,0.18);color:#cbd5e1;text-transform:uppercase;border-radius:999px">Built-in</span>[/if] | |
| 110 | [if:$loop1.is_custom]<span class="pill" style="font-size:9.5px;letter-spacing:1px;padding:2px 7px;background:rgba(15,118,110,0.18);color:#6ee7b7;text-transform:uppercase;border-radius:999px">Custom</span>[/if] | |
| 111 | </div> | |
| 112 | [if:$loop1.has_features] | |
| 113 | <ul style="margin:0;padding-left:18px"> | |
| 114 | [loop:@features]<li class="text-xs text-dim" style="margin:3px 0">$loop2.label</li>[/loop] | |
| 115 | </ul> | |
| 116 | [/if] | |
| 117 | [if:!$loop1.has_features] | |
| 118 | <div class="text-xs text-dim" style="font-style:italic">No permissions granted yet.</div> | |
| 119 | [/if] | |
| 120 | ||
| 121 | [if:$loop1.is_custom] | |
| 122 | <details style="margin-top:4px"> | |
| 123 | <summary style="cursor:pointer;font-size:12px;color:var(--accent);user-select:none">Edit role</summary> | |
| 124 | <form method="POST" action="/team.cgi" style="margin-top:10px;display:flex;flex-direction:column;gap:8px"> | |
| 125 | <input type="hidden" name="action" value="update_role_perms"> | |
| 126 | <input type="hidden" name="role_id" value="$loop1.id"> | |
| 127 | <label class="text-xs text-dim" style="display:block"> | |
| 128 | Name | |
| 129 | <input class="input" type="text" name="role_name" value="$loop1.name" maxlength="120" required style="margin-top:4px"> | |
| 130 | </label> | |
| 131 | <div class="text-xs text-dim" style="margin-top:4px">Permissions</div> | |
| 132 | <div style="display:flex;flex-direction:column;gap:4px;max-height:180px;overflow:auto;padding:6px;background:rgba(15,23,42,0.4);border-radius:6px"> | |
| 133 | [loop:@feature_options] | |
| 134 | <label class="text-xs" style="display:flex;align-items:center;gap:6px;color:var(--text-2);cursor:pointer"> | |
| 135 | <input type="checkbox" name="feature_ids" value="$loop2.id"$loop2.checked_attr> | |
| 136 | $loop2.label | |
| 137 | </label> | |
| 138 | [/loop] | |
| 139 | </div> | |
| 140 | <div style="display:flex;gap:6px;margin-top:6px"> | |
| 141 | <button type="submit" class="btn btn-secondary btn-sm">Save</button> | |
| 142 | </div> | |
| 143 | </form> | |
| 144 | <form method="POST" action="/team.cgi" style="margin-top:8px" | |
| 145 | data-confirm-title="Delete this role?" | |
| 146 | data-confirm-message="Members using this role must be reassigned first or this delete will fail." | |
| 147 | data-confirm-label="Delete role" | |
| 148 | data-confirm-style="danger"> | |
| 149 | <input type="hidden" name="action" value="delete_role"> | |
| 150 | <input type="hidden" name="role_id" value="$loop1.id"> | |
| 151 | <button type="submit" class="btn btn-danger btn-sm" style="font-size:11px;padding:4px 10px">Delete role</button> | |
| 152 | </form> | |
| 153 | </details> | |
| 154 | [/if] | |
| 155 | </div> | |
| 156 | [/loop] | |
| 157 | </div> | |
| 158 | ||
| 159 | [if:$has_features_catalog] | |
| 160 | <details style="margin-top:14px"> | |
| 161 | <summary style="cursor:pointer;color:var(--accent);font-weight:600;user-select:none">+ Create a custom role</summary> | |
| 162 | <form method="POST" action="/team.cgi" style="margin-top:12px;padding:14px;border:1px solid var(--border);border-radius:8px;background:rgba(255,255,255,0.02);display:flex;flex-direction:column;gap:10px"> | |
| 163 | <input type="hidden" name="action" value="create_role"> | |
| 164 | <label class="text-xs text-dim"> | |
| 165 | Role name | |
| 166 | <input class="input" type="text" name="role_name" placeholder="e.g. Storefront editor, Reports analyst" maxlength="120" required style="margin-top:4px"> | |
| 167 | </label> | |
| 168 | <div class="text-xs text-dim" style="margin-top:4px">Pick the permissions this role grants. You can edit the list later.</div> | |
| 169 | <div style="display:grid;grid-template-columns:1fr 1fr;gap:4px 18px;padding:10px;background:rgba(15,23,42,0.4);border-radius:6px"> | |
| 170 | [loop:@create_feature_options] | |
| 171 | <label class="text-xs" style="display:flex;align-items:center;gap:6px;color:var(--text-2);cursor:pointer"> | |
| 172 | <input type="checkbox" name="feature_ids" value="$loop1.id"> | |
| 173 | $loop1.label | |
| 174 | </label> | |
| 175 | [/loop] | |
| 176 | </div> | |
| 177 | <div> | |
| 178 | <button type="submit" class="btn btn-primary btn-sm">Create role</button> | |
| 179 | </div> | |
| 180 | </form> | |
| 181 | </details> | |
| 182 | [/if] | |
| 183 | </div> | |
| 184 | </div> | |
| 185 | [/if] | |
| 186 | ||
| 187 | <div class="module mt-3"> | |
| 188 | <div class="module-head"> | |
| 189 | <div class="left"> | |
| 190 | <div class="module-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></div> | |
| 191 | <div> | |
| 192 | <div class="module-title">Add team member</div> | |
| 193 | <div class="module-sub">Set their starting password — they can change it after first login.</div> | |
| 194 | </div> | |
| 195 | </div> | |
| 196 | </div> | |
| 197 | <div class="module-body"> | |
| 198 | [if:$has_roles] | |
| 199 | <form method="post" action="/team.cgi"> | |
| 200 | <input type="hidden" name="action" value="add_member"> | |
| 201 | <div class="dash-grid-2" style="gap:12px"> | |
| 202 | <div class="form-group"> | |
| 203 | <label class="form-label">Display name</label> | |
| 204 | <input class="input" name="display_name" required maxlength="120" placeholder="e.g. Jordan Lee"> | |
| 205 | </div> | |
| 206 | <div class="form-group"> | |
| 207 | <label class="form-label">Email</label> | |
| 208 | <input class="input" name="email" type="email" required maxlength="191" placeholder="teammate@example.com"> | |
| 209 | </div> | |
| 210 | </div> | |
| 211 | <div class="dash-grid-2" style="gap:12px"> | |
| 212 | <div class="form-group"> | |
| 213 | <label class="form-label">Starting password</label> | |
| 214 | <input class="input" name="password" type="text" required minlength="8" placeholder="Min 8 chars"> | |
| 215 | <div class="form-help">Hand this to them directly. They can change it from their own settings page.</div> | |
| 216 | </div> | |
| 217 | <div class="form-group"> | |
| 218 | <label class="form-label">Role</label> | |
| 219 | <select class="select" name="permission_groups_id" required> | |
| 220 | [loop:@add_role_options]<option value="$loop1.value">$loop1.label</option>[/loop] | |
| 221 | </select> | |
| 222 | <div class="form-help">Manager = full minus billing. Editor = day-to-day operations. Viewer = read-only.</div> | |
| 223 | </div> | |
| 224 | </div> | |
| 225 | <div style="margin-top:12px"> | |
| 226 | <button type="submit" class="btn btn-primary">Add team member</button> | |
| 227 | </div> | |
| 228 | </form> | |
| 229 | [/if] | |
| 230 | [if:!$has_roles] | |
| 231 | <div class="text-xs text-dim">No roles available yet — run the DB migration to install the default Manager / Editor / Viewer roles.</div> | |
| 232 | [/if] | |
| 233 | </div> | |
| 234 | </div> | |
| 235 | [/if] | |
| 236 | ||
| 237 | <div class="page-foot-spacer"></div> |