Skip to content
Open
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
9 changes: 7 additions & 2 deletions apps/backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

node_modules
# OS
.DS_Store

Expand All @@ -27,7 +27,12 @@ lerna-debug.log*
*.launch
.settings/
*.sublime-workspace

node_modules/
node_modules
node_modules/*
/node_modules/**/*
../node_modules
../../node_modules/*
# IDE - VSCode
.vscode/*
!.vscode/settings.json
Expand Down
20 changes: 20 additions & 0 deletions apps/backend/src/clients/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import api from './client';
import { setTokens } from '../utils/token';

export const login = async (email: string, password: string) => {
const response = await api.post('/auth/login', { email, password });

const { accessToken, refreshToken } = response.data;

Check failure on line 7 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe assignment of an `any` value
// TODO: Handle token storage and expiration properly
setTokens(accessToken, refreshToken);

Check failure on line 9 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string`

Check failure on line 9 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string`

return response.data;

Check failure on line 11 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe return of a value of type `any`
};

export const register = async (data: any) => {

Check failure on line 14 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
return api.post('/auth/register', data);
};

export const logout = async () => {
await api.post('/auth/logout');
};
98 changes: 98 additions & 0 deletions apps/backend/src/clients/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import axios, { AxiosError } from 'axios';
import { getAccessToken, getRefreshToken, setTokens, } from '../utils/token';
import { clearTokens } from '../utils/token';

declare global {
namespace NodeJS {

Check failure on line 6 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

ES2015 module syntax is preferred over namespaces
interface ProcessEnv {
VITE_API_URL?: string;
}
}
}

const api = axios.create({
baseURL: process.env.VITE_API_URL || 'http://localhost:3001',
withCredentials: true,
});



api.interceptors.request.use(

Check failure on line 20 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe assignment of an `any` value
(config) => {
const token = getAccessToken();

if (token) {
config.headers.Authorization = `Bearer ${token}`;
}

return config;

Check failure on line 28 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Expected the Promise rejection reason to be an Error
},
(error) => Promise.reject(error),
);


Check failure on line 33 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
// 🔄 RESPONSE INTERCEPTOR (Refresh Flow)
let isRefreshing = false;

Check failure on line 35 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
let failedQueue: any[] = [];

const processQueue = (error: any, token: string | null = null) => {
failedQueue.forEach((prom) => {
if (error) prom.reject(error);
else prom.resolve(token);
});

failedQueue = [];
};

api.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
const originalRequest: any = error.config;

if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
}).then((token) => {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
return api(originalRequest);
});
}

originalRequest._retry = true;
isRefreshing = true;

try {
const refreshToken = getRefreshToken();

const response = await axios.post(
`${process.env.VITE_API_URL}/auth/refresh`,
{ refreshToken },
);

const { accessToken, refreshToken: newRefreshToken } = response.data;

setTokens(accessToken, newRefreshToken);

processQueue(null, accessToken);

originalRequest.headers['Authorization'] = 'Bearer ' + accessToken;

return api(originalRequest);
} catch (err) {
processQueue(err, null);
clearTokens();
if (typeof globalThis.window !== 'undefined') {
globalThis.window.location.href = '/login';
}
return Promise.reject(err);
} finally {
isRefreshing = false;
}
}

return Promise.reject(error);
},
);

export default api;
21 changes: 21 additions & 0 deletions apps/backend/src/services/escrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import api from "src/clients/client";

export const createEscrow = async (payload: any) => {
const response = await api.post('/escrow', payload);
return response.data;
};

export const getEscrows = async () => {
const response = await api.get('/escrow');
return response.data;
};

export const getEscrowById = async (id: string) => {
const response = await api.get(`/escrow/${id}`);
return response.data;
};

export const releaseEscrow = async (id: string) => {
const response = await api.patch(`/escrow/${id}/release`);
return response.data;
};
1 change: 1 addition & 0 deletions apps/backend/src/types/types.doc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this types is is used to mitigate "any" usage
30 changes: 30 additions & 0 deletions apps/backend/src/utils/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const ACCESS_KEY = 'accessToken';
const REFRESH_KEY = 'refreshToken';

export const setTokens = (access: string, refresh: string) => {
if (typeof globalThis.window !== 'undefined') {
globalThis.window.localStorage.setItem(ACCESS_KEY, access);
globalThis.window.localStorage.setItem(REFRESH_KEY, refresh);
}
};

export const getAccessToken = () => {
if (typeof globalThis.window !== 'undefined') {
return globalThis.window.localStorage.getItem(ACCESS_KEY);
}
return null;
};

export const getRefreshToken = () => {
if (typeof globalThis.window !== 'undefined') {
return globalThis.window.localStorage.getItem(REFRESH_KEY);
}
return null;
};

export const clearTokens = () => {
if (typeof globalThis.window !== 'undefined') {
globalThis.window.localStorage.removeItem(ACCESS_KEY);
globalThis.window.localStorage.removeItem(REFRESH_KEY);
}
};
21 changes: 21 additions & 0 deletions apps/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "radix-nova",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
10 changes: 5 additions & 5 deletions apps/frontend/app/contexts/WalletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export const WalletProvider: React.FC<WalletProviderProps> = ({ children }) => {

// Load wallet from localStorage on mount
useEffect(() => {
const savedWallet = localStorage.getItem('vaultix_wallet');
const savedWallet = window.localStorage.getItem('vaultix_wallet');
if (savedWallet) {
try {
const parsedWallet = JSON.parse(savedWallet);
const parsedWallet = JSON.parse(savedWallet) as WalletConnection;
setWallet(parsedWallet);
} catch {
localStorage.removeItem('vaultix_wallet');
window.localStorage.removeItem('vaultix_wallet');
}
}
}, []);
Expand All @@ -59,7 +59,7 @@ export const WalletProvider: React.FC<WalletProviderProps> = ({ children }) => {
};

setWallet(walletConnection);
localStorage.setItem('vaultix_wallet', JSON.stringify(walletConnection));
window.localStorage.setItem('vaultix_wallet', JSON.stringify(walletConnection));
} catch (err: any) {
setError(err.message || 'Failed to connect wallet');
throw err;
Expand All @@ -70,7 +70,7 @@ export const WalletProvider: React.FC<WalletProviderProps> = ({ children }) => {

const disconnect = () => {
setWallet(null);
localStorage.removeItem('vaultix_wallet');
window.localStorage.removeItem('vaultix_wallet');
setError(null);
};

Expand Down
9 changes: 9 additions & 0 deletions apps/frontend/app/escrow/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import TimelineSection from '@/components/escrow/detail/TimelineSection';
import TransactionHistory from '@/components/escrow/detail/TransactionHistory';
import ActivityFeed from '@/components/common/ActivityFeed';
import { IEscrowExtended } from '@/types/escrow';
import FileDisputeModal from '@/components/escrow/detail/file-dispute-modal';
import { Button } from '@/components/ui/button';

const EscrowDetailPage = () => {
const { id } = useParams();
const { escrow, loading, error } = useEscrow(id as string);
const { connected, publicKey, connect } = useWallet(); // Assuming wallet hook exists
const [userRole, setUserRole] = useState<'creator' | 'counterparty' | null>(null);
const [disputeOpen, setDisputeOpen] = useState(false);

useEffect(() => {
if (escrow && publicKey) {
Expand Down Expand Up @@ -104,6 +107,12 @@ const EscrowDetailPage = () => {
</div>
</div>
</div>

<FileDisputeModal
open={disputeOpen}
onClose={() => setDisputeOpen(false)}
escrowId={escrow.id}
/>
</div>
);
};
Expand Down
Loading
Loading