Refresh org portal state and treasury interactions
- Hydrate portal/session data from login and sync payloads - Add treasury notices for credit, invite, leave, and disband actions - Improve portal cards and modal UI for members, fleet, and treasury
This commit is contained in:
parent
8a31d456f1
commit
d8812df381
File diff suppressed because one or more lines are too long
@ -25,16 +25,16 @@ ${scopeSelector} .org-members-head {
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-members-section {
|
||||
${scopeSelector} .org-members-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.85rem;
|
||||
margin-bottom: 1.25rem;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-members-section h4 {
|
||||
${scopeSelector} .org-members-kicker {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.08em;
|
||||
@ -42,6 +42,84 @@ ${scopeSelector} .org-members-section h4 {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
${scopeSelector} .org-members-subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
${scopeSelector} .org-members-tools {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-tool-btn {
|
||||
position: relative;
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
padding: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-tool-badge {
|
||||
position: absolute;
|
||||
top: -0.25rem;
|
||||
right: -0.25rem;
|
||||
min-width: 1.1rem;
|
||||
height: 1.1rem;
|
||||
padding: 0 0.2rem;
|
||||
border-radius: 999px;
|
||||
background: #b91c1c;
|
||||
color: white;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-invite-menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
right: 0;
|
||||
width: min(24rem, 100%);
|
||||
max-height: 22rem;
|
||||
overflow: auto;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: white;
|
||||
box-shadow: 0 18px 45px rgb(15 23 42 / 0.18);
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-invite-menu-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-invite-menu-title {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
${scopeSelector} .org-invite-menu-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-invite-row,
|
||||
${scopeSelector} .org-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -73,7 +151,8 @@ ${scopeSelector} .org-name-meta {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
${scopeSelector} .org-inline-actions {
|
||||
${scopeSelector} .org-inline-actions,
|
||||
${scopeSelector} .org-invite-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
@ -92,13 +171,25 @@ ${scopeSelector} .org-members-empty {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-name-row {
|
||||
${scopeSelector} .org-members-tools {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-invite-menu {
|
||||
left: 0;
|
||||
right: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-name-row,
|
||||
${scopeSelector} .org-invite-row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
${scopeSelector} .org-name-row button,
|
||||
${scopeSelector} .org-inline-actions {
|
||||
${scopeSelector} .org-inline-actions,
|
||||
${scopeSelector} .org-invite-actions {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
@ -110,6 +201,7 @@ ${scopeSelector} .org-members-empty {
|
||||
const PanelCard = window.SharedUI.componentFns.PanelCard;
|
||||
const members = store.getMembers();
|
||||
const pendingInvites = store.getPendingInvites();
|
||||
const inviteMenuOpen = store.getInviteMenuOpen();
|
||||
const allowMemberManagement = getters.canManageMembers();
|
||||
ensureScopedStyle("portal-members-card", membersCardCss);
|
||||
|
||||
@ -127,80 +219,211 @@ ${scopeSelector} .org-members-empty {
|
||||
{ className: "org-members-head" },
|
||||
h(
|
||||
"div",
|
||||
{ className: "org-members-section" },
|
||||
h("h4", null, "Pending Invites"),
|
||||
pendingInvites.length === 0
|
||||
{ className: "org-members-copy" },
|
||||
h("h4", { className: "org-members-kicker" }, "Roster"),
|
||||
h(
|
||||
"p",
|
||||
{ className: "org-members-subtitle" },
|
||||
"Manage membership and review incoming organization invites.",
|
||||
),
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ className: "org-members-tools" },
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className:
|
||||
"org-secondary-btn org-icon-btn org-tool-btn",
|
||||
title: "Pending invitations",
|
||||
"aria-label": "Pending invitations",
|
||||
onClick: () => actions.toggleInviteMenu(),
|
||||
},
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
className: "org-icon",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
"stroke-width": "2",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"aria-hidden": "true",
|
||||
},
|
||||
h("path", {
|
||||
d: "M15 17h5l-1.4-1.4A2 2 0 0 1 18 14.2V11a6 6 0 1 0-12 0v3.2a2 2 0 0 1-.6 1.4L4 17h5",
|
||||
}),
|
||||
h("path", { d: "M9.73 21a2 2 0 0 0 4.54 0" }),
|
||||
),
|
||||
pendingInvites.length > 0
|
||||
? h(
|
||||
"span",
|
||||
{ className: "org-tool-badge" },
|
||||
String(pendingInvites.length),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
allowMemberManagement
|
||||
? h(
|
||||
"p",
|
||||
{ className: "org-members-empty" },
|
||||
"No incoming organization invites.",
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className:
|
||||
"org-secondary-btn org-icon-btn org-tool-btn",
|
||||
title: "Invite player",
|
||||
"aria-label": "Invite player",
|
||||
onClick: () =>
|
||||
actions.openModal("invite"),
|
||||
},
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
className: "org-icon",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
"stroke-width": "2",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"aria-hidden": "true",
|
||||
},
|
||||
h("path", { d: "M12 5v14" }),
|
||||
h("path", { d: "M5 12h14" }),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
inviteMenuOpen
|
||||
? h(
|
||||
"div",
|
||||
{ className: "org-invite-menu" },
|
||||
h(
|
||||
"div",
|
||||
{ className: "org-invite-menu-head" },
|
||||
h(
|
||||
"h4",
|
||||
{
|
||||
className:
|
||||
"org-invite-menu-title",
|
||||
},
|
||||
"Pending Invites",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className:
|
||||
"org-secondary-btn org-icon-btn org-tool-btn",
|
||||
title: "Close invites",
|
||||
"aria-label": "Close invites",
|
||||
onClick: () =>
|
||||
actions.closeInviteMenu(),
|
||||
},
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
className: "org-icon",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
"stroke-width": "2",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"aria-hidden": "true",
|
||||
},
|
||||
h("path", { d: "M18 6 6 18" }),
|
||||
h("path", { d: "m6 6 12 12" }),
|
||||
),
|
||||
),
|
||||
),
|
||||
pendingInvites.length === 0
|
||||
? h(
|
||||
"p",
|
||||
{
|
||||
className: "org-members-empty",
|
||||
},
|
||||
"No incoming organization invites.",
|
||||
)
|
||||
: h(
|
||||
"div",
|
||||
{
|
||||
className:
|
||||
"org-invite-menu-list",
|
||||
},
|
||||
...pendingInvites.map((invite) =>
|
||||
h(
|
||||
"article",
|
||||
{
|
||||
className:
|
||||
"org-invite-row",
|
||||
},
|
||||
h(
|
||||
"div",
|
||||
{
|
||||
className:
|
||||
"org-name-copy",
|
||||
},
|
||||
h(
|
||||
"strong",
|
||||
null,
|
||||
invite.orgName ||
|
||||
"Unknown Organization",
|
||||
),
|
||||
h(
|
||||
"span",
|
||||
{
|
||||
className:
|
||||
"org-name-meta",
|
||||
},
|
||||
"Invited by ",
|
||||
invite.inviterName ||
|
||||
"Unknown",
|
||||
),
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{
|
||||
className:
|
||||
"org-invite-actions",
|
||||
},
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className:
|
||||
"org-secondary-btn",
|
||||
onClick: () =>
|
||||
actions.declineInvite(
|
||||
String(
|
||||
invite.orgId ||
|
||||
"",
|
||||
),
|
||||
),
|
||||
},
|
||||
"Decline",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
onClick: () =>
|
||||
actions.acceptInvite(
|
||||
String(
|
||||
invite.orgId ||
|
||||
"",
|
||||
),
|
||||
),
|
||||
},
|
||||
"Accept",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
allowMemberManagement
|
||||
? h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "org-secondary-btn",
|
||||
onClick: () => actions.openModal("invite"),
|
||||
},
|
||||
"Invite Player",
|
||||
)
|
||||
: null,
|
||||
),
|
||||
...pendingInvites.map((invite) =>
|
||||
h(
|
||||
"article",
|
||||
{ className: "org-name-row" },
|
||||
h(
|
||||
"div",
|
||||
{ className: "org-name-copy" },
|
||||
h(
|
||||
"strong",
|
||||
null,
|
||||
invite.orgName || "Unknown Organization",
|
||||
),
|
||||
h(
|
||||
"span",
|
||||
{ className: "org-name-meta" },
|
||||
"Invited by ",
|
||||
invite.inviterName || "Unknown",
|
||||
),
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ className: "org-inline-actions" },
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "org-secondary-btn",
|
||||
onClick: () =>
|
||||
actions.declineInvite(
|
||||
String(invite.orgId || ""),
|
||||
),
|
||||
},
|
||||
"Decline",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
onClick: () =>
|
||||
actions.acceptInvite(
|
||||
String(invite.orgId || ""),
|
||||
),
|
||||
},
|
||||
"Accept",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ className: "org-members-section" },
|
||||
h("h4", null, "Roster"),
|
||||
),
|
||||
...members.map((member) => {
|
||||
const canRemoveMember =
|
||||
|
||||
@ -85,6 +85,14 @@
|
||||
store.setModal(null);
|
||||
}
|
||||
|
||||
toggleInviteMenu() {
|
||||
store.setInviteMenuOpen(!store.getInviteMenuOpen());
|
||||
}
|
||||
|
||||
closeInviteMenu() {
|
||||
store.setInviteMenuOpen(false);
|
||||
}
|
||||
|
||||
removeMember(member) {
|
||||
if (!getters.canManageMembers()) {
|
||||
return false;
|
||||
@ -355,6 +363,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
this.closeInviteMenu();
|
||||
return bridge.requestAcceptInvite({ orgId });
|
||||
}
|
||||
|
||||
@ -371,6 +380,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
this.closeInviteMenu();
|
||||
return bridge.requestDeclineInvite({ orgId });
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +73,8 @@
|
||||
text: "",
|
||||
});
|
||||
[this.getModal, this.setModal] = createSignal(null);
|
||||
[this.getInviteMenuOpen, this.setInviteMenuOpen] =
|
||||
createSignal(false);
|
||||
[this.getOrgDisbanded, this.setOrgDisbanded] = createSignal(false);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user