Skip to content

Commit ecb7f08

Browse files
authored
Merge pull request #994 from HiEventsDev/develop
2 parents 4d6360f + 0bcaed7 commit ecb7f08

11 files changed

Lines changed: 527 additions & 423 deletions

File tree

README.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,6 @@ managed option with zero setup, automatic updates, and managed infrastructure.
164164

165165
<br>
166166

167-
## Documentation
168-
169-
| Resource | Link |
170-
|:----------------|:----------------------------------------------------------------------------------------------|
171-
| Getting Started | [hi.events/docs/getting-started](https://hi.events/docs/getting-started?utm_source=gh-readme) |
172-
| Configuration | [hi.events/docs/configuration](https://hi.events/docs/configuration?utm_source=gh-readme) |
173-
| API Reference | [hi.events/docs/api](https://hi.events/docs/api?utm_source=gh-readme) |
174-
| Webhooks | [hi.events/docs/webhooks](https://hi.events/docs/webhooks?utm_source=gh-readme) |
175-
176-
<br>
177-
178167
## Contributing
179168

180169
We welcome contributions. See the [contributing guide](CONTRIBUTING.md) for details.

backend/app/Services/Domain/Message/MessagingEligibilityService.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,19 @@ public function __construct(
3030

3131
public function checkEligibility(int $accountId, int $eventId): ?MessagingEligibilityFailureDTO
3232
{
33-
$failures = [];
34-
3533
$account = $this->accountRepository
3634
->loadRelation(AccountStripePlatformDomainObject::class)
3735
->findById($accountId);
3836

37+
$tier = $this->getAccountMessagingTier($account->getAccountMessagingTierId());
38+
39+
// Trusted and Premium tiers bypass eligibility checks
40+
if ($tier->getName() !== self::UNTRUSTED_TIER_NAME) {
41+
return null;
42+
}
43+
44+
$failures = [];
45+
3946
if (!$account->isStripeSetupComplete()) {
4047
$failures[] = MessagingEligibilityFailureEnum::STRIPE_NOT_CONNECTED;
4148
}
@@ -69,11 +76,11 @@ public function checkTierLimits(int $accountId, int $recipientCount, string $mes
6976

7077
$messagesInLast24h = $this->messageRepository->countMessagesInLast24Hours($accountId);
7178
if ($messagesInLast24h >= $tier->getMaxMessagesPer24h()) {
72-
// $violations[] = MessagingTierViolationEnum::MESSAGE_LIMIT_EXCEEDED;
79+
$violations[] = MessagingTierViolationEnum::MESSAGE_LIMIT_EXCEEDED;
7380
}
7481

7582
if ($recipientCount > $tier->getMaxRecipientsPerMessage()) {
76-
// $violations[] = MessagingTierViolationEnum::RECIPIENT_LIMIT_EXCEEDED;
83+
$violations[] = MessagingTierViolationEnum::RECIPIENT_LIMIT_EXCEEDED;
7784
}
7885

7986
if (!$tier->getLinksAllowed() && $this->containsLinks($messageContent)) {

frontend/src/components/common/AdminEventsTable/AdminEventsTable.module.scss

Lines changed: 0 additions & 13 deletions
This file was deleted.

frontend/src/components/common/AdminEventsTable/index.tsx

Lines changed: 113 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {t} from "@lingui/macro";
33
import {AdminEvent} from "../../../api/admin.client";
44
import {IconChevronDown, IconChevronUp, IconEye, IconUserCheck} from "@tabler/icons-react";
55
import {IdParam} from "../../../types";
6-
import classes from "./AdminEventsTable.module.scss";
6+
import tableStyles from "../../../styles/admin-table.module.scss";
77

88
interface AdminEventsTableProps {
99
events: AdminEvent[];
@@ -18,7 +18,7 @@ interface AdminEventsTableProps {
1818
const AdminEventsTable = ({events, onSort, sortBy, sortDirection, onViewEvent, onImpersonate, isImpersonating}: AdminEventsTableProps) => {
1919
if (!events || events.length === 0) {
2020
return (
21-
<div className={classes.emptyState}>
21+
<div className={tableStyles.emptyState}>
2222
<Text size="lg" c="dimmed">{t`No events found`}</Text>
2323
</div>
2424
);
@@ -68,113 +68,118 @@ const AdminEventsTable = ({events, onSort, sortBy, sortDirection, onViewEvent, o
6868
};
6969

7070
return (
71-
<div className={classes.tableContainer}>
72-
<Table striped highlightOnHover>
73-
<Table.Thead>
74-
<Table.Tr>
75-
<Table.Th>
76-
<Button
77-
variant="subtle"
78-
size="compact-sm"
79-
onClick={() => handleSort('title')}
80-
rightSection={<SortIcon column="title" />}
81-
>
82-
{t`Event Title`}
83-
</Button>
84-
</Table.Th>
85-
<Table.Th>{t`Organizer`}</Table.Th>
86-
<Table.Th>
87-
<Button
88-
variant="subtle"
89-
size="compact-sm"
90-
onClick={() => handleSort('start_date')}
91-
rightSection={<SortIcon column="start_date" />}
92-
>
93-
{t`Start Date`}
94-
</Button>
95-
</Table.Th>
96-
<Table.Th>
97-
<Button
98-
variant="subtle"
99-
size="compact-sm"
100-
onClick={() => handleSort('end_date')}
101-
rightSection={<SortIcon column="end_date" />}
102-
>
103-
{t`End Date`}
104-
</Button>
105-
</Table.Th>
106-
<Table.Th>{t`Statistics`}</Table.Th>
107-
<Table.Th>{t`Status`}</Table.Th>
108-
<Table.Th>{t`Actions`}</Table.Th>
109-
</Table.Tr>
110-
</Table.Thead>
111-
<Table.Tbody>
112-
{events.map((event) => (
113-
<Table.Tr key={event.id}>
114-
<Table.Td>
115-
<Text fw={500}>{event.title}</Text>
116-
</Table.Td>
117-
<Table.Td>
118-
<Text size="sm">{event.organizer_name}</Text>
119-
</Table.Td>
120-
<Table.Td>
121-
<Text size="sm">{formatDate(event.start_date)}</Text>
122-
</Table.Td>
123-
<Table.Td>
124-
<Text size="sm">{formatDate(event.end_date)}</Text>
125-
</Table.Td>
126-
<Table.Td>
127-
{event.statistics ? (
128-
<Stack gap={4}>
129-
<Group gap={6}>
130-
<Text size="xs" c="dimmed">{t`Sales:`}</Text>
131-
<Text size="xs" fw={600}>{formatCurrency(event.statistics.total_gross_sales)}</Text>
132-
</Group>
133-
<Group gap={6}>
134-
<Text size="xs" c="dimmed">{t`Attendees:`}</Text>
135-
<Text size="xs" fw={500}>{formatNumber(event.statistics.attendees_registered)}</Text>
136-
</Group>
137-
<Group gap={6}>
138-
<Text size="xs" c="dimmed">{t`Orders:`}</Text>
139-
<Text size="xs" fw={500}>{formatNumber(event.statistics.orders_created)}</Text>
140-
</Group>
141-
</Stack>
142-
) : (
143-
<Text size="sm" c="dimmed">-</Text>
144-
)}
145-
</Table.Td>
146-
<Table.Td>
147-
<Badge color={getStatusBadgeColor(event.status)}>
148-
{event.status}
149-
</Badge>
150-
</Table.Td>
151-
<Table.Td>
152-
<Group gap="xs">
153-
<Tooltip label={t`View Event`}>
154-
<ActionIcon
155-
variant="subtle"
156-
color="blue"
157-
onClick={() => onViewEvent?.(event)}
158-
>
159-
<IconEye size={18} />
160-
</ActionIcon>
161-
</Tooltip>
162-
<Tooltip label={t`Impersonate User`}>
163-
<ActionIcon
164-
variant="subtle"
165-
color="grape"
166-
onClick={() => onImpersonate?.(event.user_id, event.account_id)}
167-
disabled={isImpersonating}
168-
>
169-
<IconUserCheck size={18} />
170-
</ActionIcon>
171-
</Tooltip>
172-
</Group>
173-
</Table.Td>
71+
<div className={tableStyles.tableWrapper}>
72+
<div className={tableStyles.tableScroll}>
73+
<Table className={tableStyles.table} highlightOnHover>
74+
<Table.Thead>
75+
<Table.Tr>
76+
<Table.Th>
77+
<Button
78+
variant="subtle"
79+
size="compact-sm"
80+
onClick={() => handleSort('title')}
81+
rightSection={<SortIcon column="title" />}
82+
className={tableStyles.sortButton}
83+
>
84+
{t`Event Title`}
85+
</Button>
86+
</Table.Th>
87+
<Table.Th>{t`Organizer`}</Table.Th>
88+
<Table.Th>
89+
<Button
90+
variant="subtle"
91+
size="compact-sm"
92+
onClick={() => handleSort('start_date')}
93+
rightSection={<SortIcon column="start_date" />}
94+
className={tableStyles.sortButton}
95+
>
96+
{t`Start Date`}
97+
</Button>
98+
</Table.Th>
99+
<Table.Th>
100+
<Button
101+
variant="subtle"
102+
size="compact-sm"
103+
onClick={() => handleSort('end_date')}
104+
rightSection={<SortIcon column="end_date" />}
105+
className={tableStyles.sortButton}
106+
>
107+
{t`End Date`}
108+
</Button>
109+
</Table.Th>
110+
<Table.Th>{t`Statistics`}</Table.Th>
111+
<Table.Th>{t`Status`}</Table.Th>
112+
<Table.Th>{t`Actions`}</Table.Th>
174113
</Table.Tr>
175-
))}
176-
</Table.Tbody>
177-
</Table>
114+
</Table.Thead>
115+
<Table.Tbody>
116+
{events.map((event) => (
117+
<Table.Tr key={event.id}>
118+
<Table.Td>
119+
<Text fw={500}>{event.title}</Text>
120+
</Table.Td>
121+
<Table.Td>
122+
<Text size="sm">{event.organizer_name}</Text>
123+
</Table.Td>
124+
<Table.Td>
125+
<Text size="sm">{formatDate(event.start_date)}</Text>
126+
</Table.Td>
127+
<Table.Td>
128+
<Text size="sm">{formatDate(event.end_date)}</Text>
129+
</Table.Td>
130+
<Table.Td>
131+
{event.statistics ? (
132+
<Stack gap={4}>
133+
<Group gap={6}>
134+
<Text size="xs" c="dimmed">{t`Sales:`}</Text>
135+
<Text size="xs" fw={600}>{formatCurrency(event.statistics.total_gross_sales)}</Text>
136+
</Group>
137+
<Group gap={6}>
138+
<Text size="xs" c="dimmed">{t`Attendees:`}</Text>
139+
<Text size="xs" fw={500}>{formatNumber(event.statistics.attendees_registered)}</Text>
140+
</Group>
141+
<Group gap={6}>
142+
<Text size="xs" c="dimmed">{t`Orders:`}</Text>
143+
<Text size="xs" fw={500}>{formatNumber(event.statistics.orders_created)}</Text>
144+
</Group>
145+
</Stack>
146+
) : (
147+
<Text size="sm" c="dimmed">-</Text>
148+
)}
149+
</Table.Td>
150+
<Table.Td>
151+
<Badge color={getStatusBadgeColor(event.status)} variant="light">
152+
{event.status}
153+
</Badge>
154+
</Table.Td>
155+
<Table.Td>
156+
<Group gap="xs">
157+
<Tooltip label={t`View Event`}>
158+
<ActionIcon
159+
variant="subtle"
160+
color="blue"
161+
onClick={() => onViewEvent?.(event)}
162+
>
163+
<IconEye size={18} />
164+
</ActionIcon>
165+
</Tooltip>
166+
<Tooltip label={t`Impersonate User`}>
167+
<ActionIcon
168+
variant="subtle"
169+
color="grape"
170+
onClick={() => onImpersonate?.(event.user_id, event.account_id)}
171+
disabled={isImpersonating}
172+
>
173+
<IconUserCheck size={18} />
174+
</ActionIcon>
175+
</Tooltip>
176+
</Group>
177+
</Table.Td>
178+
</Table.Tr>
179+
))}
180+
</Table.Tbody>
181+
</Table>
182+
</div>
178183
</div>
179184
);
180185
};

frontend/src/components/common/AdminOrdersTable/AdminOrdersTable.module.scss

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)