Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions apps/web/src/app/invitations/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use client';

import { RightSidebar } from '@/components/layout/RightSidebar';
import { Search } from 'lucide-react';

const InvitationsPage = () => {
return (
<div className="flex w-full min-h-screen">
<main className="flex flex-1 flex-col w-full min-h-screen px-5 pr-16">
<header className="flex items-center justify-between p-4 border-b border-gray-800">
<h1 className="text-2xl font-semibold text-white">My invitations</h1>
</header>

<section className="flex-1 px-4 pb-4">
<div className="bg-secondary rounded-xl p-4 mt-4">
<div className="flex items-center justify-between mb-4">
<div className="relative w-full max-w-md">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
<Search className="w-4 h-4" />
</span>
<input
type="text"
placeholder="Search an invitation..."
className="w-full pl-9 pr-3 py-2 rounded-md bg-background text-white placeholder:text-gray-400 border border-gray-800 focus:outline-none focus:ring-2 focus:ring-primary/60"
disabled
/>
</div>

<div className="flex items-center gap-2">
<div className="text-sm text-gray-400">Rows per page</div>
<div className="text-sm text-white">10</div>
</div>
</div>

<div className="w-full overflow-hidden rounded-lg border border-gray-800">
<div className="grid grid-cols-7 text-xs font-medium text-gray-300 uppercase tracking-wide bg-[#0B1D39]">
<div className="py-3 px-4">Property</div>
<div className="py-3 px-4">Owner</div>
<div className="py-3 px-4">Check-in</div>
<div className="py-3 px-4">Check-out</div>
<div className="py-3 px-4">Created</div>
<div className="py-3 px-4">Status</div>
<div className="py-3 px-4">Invitation</div>
</div>

<div className="py-16 text-center text-gray-300 bg-[#071429]">
No invitations sent yet
</div>
</div>

<div className="flex items-center justify-between mt-4 text-sm text-gray-400">
<div>Total: 0 invitations</div>
<div className="flex items-center gap-2">
<button
type="button"
className="px-3 py-1 rounded-md bg-[#0B1D39] border border-gray-800 text-gray-300"
disabled
>
Previous
</button>
<button
type="button"
className="px-3 py-1 rounded-md bg-[#0B1D39] border border-gray-800 text-gray-300"
disabled
>
Next
</button>
</div>
</div>
</div>
</section>
</main>

<RightSidebar />
</div>
);
};

export default InvitationsPage;
4 changes: 1 addition & 3 deletions apps/web/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ export default function Home() {
return (
<div className="flex w-full min-h-screen">
<main className="flex flex-1 flex-col w-full min-h-screen px-5 pr-16">
<header className="flex items-center justify-between p-4 border-b border-gray-800">
<Image src="/stellarrentlogo.png" alt="StellaRent" width={100} height={100} />
</header>
<header className="flex items-center justify-between p-4 border-b border-gray-800"></header>

<section className="p-4">
<SearchBar />
Expand Down
87 changes: 36 additions & 51 deletions apps/web/src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ interface ChallengeResponse {
const _apiCall = async <T>(endpoint: string, options: RequestInit = {}): Promise<T> => {
const url = `${API_BASE_URL}${endpoint}`;
const token = localStorage.getItem('authToken');

const headers = new Headers({
'Content-Type': 'application/json',
...(token && { 'Authorization': `Bearer ${token}` }),
...(options.headers as Record<string, string> || {})
...(token && { Authorization: `Bearer ${token}` }),
...((options.headers as Record<string, string>) || {}),
});

try {
const response = await fetch(url, {
...options,
headers,
credentials: 'include'
credentials: 'include',
});

if (!response.ok) {
Expand All @@ -77,29 +77,6 @@ const _apiCall = async <T>(endpoint: string, options: RequestInit = {}): Promise
console.error(`API call failed for ${endpoint}:`, error);
throw error;
}

const config: RequestInit = {
headers: {
'Content-Type': 'application/json',
...(token && { Authorization: `Bearer ${token}` }),
...options.headers,
},
...options,
};

try {
const response = await fetch(url, config);

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
}

return await response.json();
} catch (error) {
console.error('API request failed:', error);
throw error;
}
};

// Transform wallet user function
Expand Down Expand Up @@ -289,6 +266,10 @@ export const propertyAPI = {
return apiUtils.request(`/properties/${propertyId}/availability`, {
method: 'PUT',
body: JSON.stringify(availability),
});
},
};

export const walletAPI = {
getWalletBalance: async (userId: string) => {
try {
Expand All @@ -303,18 +284,18 @@ export const walletAPI = {
return {
success: false,
data: { balance: 0, currency: 'USD' },
message: 'Failed to load wallet balance'
message: 'Failed to load wallet balance',
};
}
},

getTransactionHistory: async (userId: string, filters?: Record<string, unknown>) => {
try {
const params = new URLSearchParams({ userId });
if (filters) {
Object.entries(filters).forEach(([key, value]) => {
for (const [key, value] of Object.entries(filters)) {
if (value) params.append(key, String(value));
});
}
}
const response = await fetch(`/api/wallets/${userId}/transactions?${params}`);
if (!response.ok) {
Expand All @@ -327,11 +308,11 @@ export const walletAPI = {
return {
success: false,
data: [],
message: 'Failed to load transaction history'
message: 'Failed to load transaction history',
};
}
},

addFunds: async (userId: string, amount: number, paymentMethod: string) => {
try {
const response = await fetch(`/api/wallets/${userId}/deposit`, {
Expand All @@ -348,8 +329,12 @@ export const walletAPI = {
throw new Error('Failed to process deposit');
}
},

withdrawFunds: async (userId: string, amount: number, accountDetails: Record<string, unknown>) => {

withdrawFunds: async (
userId: string,
amount: number,
accountDetails: Record<string, unknown>
) => {
try {
const response = await fetch(`/api/wallets/${userId}/withdraw`, {
method: 'POST',
Expand All @@ -368,9 +353,9 @@ export const walletAPI = {
};

export const notificationAPI = {
async getNotifications(userId: string, filters?: Record<string, unknown>) {
{{ ... }}
});
async getNotifications(_userId: string, _filters?: Record<string, unknown>) {
// TODO: Implement notifications API
return Promise.resolve({ data: [], success: true });
},
};

Expand All @@ -391,13 +376,13 @@ export const dashboardAPI = {
totalBookings: 0,
totalEarnings: 0,
activeListings: 0,
pendingRequests: 0
pendingRequests: 0,
},
message: 'Failed to load dashboard stats'
message: 'Failed to load dashboard stats',
};
}
},

getRecentActivity: async (userId: string, userType: 'host' | 'tenant') => {
try {
const response = await fetch(`/api/activity/recent?userId=${userId}&userType=${userType}`);
Expand All @@ -411,18 +396,18 @@ export const dashboardAPI = {
return {
success: false,
data: [],
message: 'Failed to load recent activity'
message: 'Failed to load recent activity',
};
}
},

getEarningsAnalytics: async (userId: string, dateRange?: Record<string, unknown>) => {
try {
const params = new URLSearchParams({ userId });
if (dateRange) {
Object.entries(dateRange).forEach(([key, value]) => {
for (const [key, value] of Object.entries(dateRange)) {
if (value) params.append(key, String(value));
});
}
}
const response = await fetch(`/api/analytics/earnings?${params}`);
if (!response.ok) {
Expand All @@ -435,11 +420,11 @@ export const dashboardAPI = {
return {
success: false,
data: [],
message: 'Failed to load earnings analytics'
message: 'Failed to load earnings analytics',
};
}
},

getBookingAnalytics: async (
userId: string,
userType: 'host' | 'tenant',
Expand All @@ -448,9 +433,9 @@ export const dashboardAPI = {
try {
const params = new URLSearchParams({ userId, userType });
if (dateRange) {
Object.entries(dateRange).forEach(([key, value]) => {
for (const [key, value] of Object.entries(dateRange)) {
if (value) params.append(key, String(value));
});
}
}
const response = await fetch(`/api/analytics/bookings?${params}`);
if (!response.ok) {
Expand All @@ -463,15 +448,15 @@ export const dashboardAPI = {
return {
success: false,
data: [],
message: 'Failed to load booking analytics'
message: 'Failed to load booking analytics',
};
}
},
};

export const authAPI = {
async login(email: string, password: string) {
{{ ... }}
return apiUtils.request('/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
});
Expand Down
6 changes: 6 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading