@@ -383,13 +391,13 @@
{{ game.amount }} pts
- {{ new Date(game.created_at).toLocaleTimeString() }}
+ {{ new Date(game.began_at).toLocaleDateString() }} • {{ new
+ Date(game.began_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) }}
- Marks: {{ game.details.marks }}
Capotes: {{ game.details.capotes }}
Bandeiras: {{ game.details.bandeiras }}
@@ -579,7 +587,6 @@ const error = ref(null)
const activeTab = ref('info')
const fileInput = ref(null)
-// Profile form
const profileForm = reactive({
name: '',
nickname: ''
@@ -588,7 +595,6 @@ const updatingProfile = ref(false)
const profileMessage = ref('')
const profileMessageType = ref('')
-// Password form
const passwordForm = reactive({
current_password: '',
new_password: '',
@@ -598,7 +604,6 @@ const updatingPassword = ref(false)
const passwordMessage = ref('')
const passwordMessageType = ref('')
-// Delete account
const deleteConfirmEmail = ref('')
const showDeleteConfirmation = ref(false)
const deletingAccount = ref(false)
@@ -622,13 +627,12 @@ const filters = ref({
startDate: '',
endDate: '',
sort: {
- column: 'created_at',
+ column: 'began_at',
order: 'desc'
}
});
const handleSortChange = (column) => {
- // If clicking same column, toggle order, else default to desc
if (filters.value.sort.column === column) {
filters.value.sort.order = filters.value.sort.order === 'asc' ? 'desc' : 'asc';
} else {
@@ -660,18 +664,26 @@ const fetchData = async () => {
try {
let newData = [];
- if (isTransaction) {
- // const response = await apiStore.getTransactions(params);
- // Logic: if response.data.length < limit, set hasMore.value = false
- for (let i = 0; i < 15; i++) {
- newData.push({
- id: `txn_${Date.now()}_${i}`,
- amount: Math.floor(Math.random() * 1000),
- type: Math.random() > 0.5 ? 'credit' : 'debit',
- created_at: new Date().toISOString()
- });
- }
+ if (isTransaction) {
+ const apiParams = {
+ page: state.page,
+ type: filters.value.type === 'credit' ? 'C' : filters.value.type === 'debit' ? 'D' : undefined,
+ date_from: filters.value.startDate || undefined,
+ date_to: filters.value.endDate || undefined,
+ };
+
+ const response = await apiStore.getCurrentUserTransactions(apiParams);
+ const apiTxns = response.data.data;
+
+ newData = apiTxns.map(txn => ({
+ id: txn.id.toString(),
+ type: txn.type.type === 'D' ? 'debit' : 'credit',
+ category: txn.type.name,
+ amount: Math.abs(txn.coins),
+ began_at: txn.transaction_datetime,
+ reference: txn.match_id ? `Match #${txn.match_id}` : txn.game_id ? `Game #${txn.game_id}` : 'N/A'
+ }));
transactions.value.push(...newData);
}
@@ -680,25 +692,24 @@ const fetchData = async () => {
const apiParams = {
page: state.page,
type: filters.value.variant !== 'all' ? filters.value.variant : undefined,
- status: filters.value.outcome !== 'all' ? 'Ended' : undefined,
+ outcome: filters.value.outcome !== 'all' ? filters.value.outcome : undefined,
+ status: 'Ended',
+ date_from: filters.value.startDate || undefined,
+ date_to: filters.value.endDate || undefined,
sort_by: filters.value.sort.column,
- sort_direction: filters.value.sort.order
+ sort_direction: filters.value.sort.order,
};
const response = await apiStore.getCurrentUserMatches(apiParams);
- const apiGames = response.data.data
+ const apiGames = response.data.data;
newData = apiGames.map(game => {
- const isPlayer1 = game.player1_user_id === authStore.currentUserID;
+ const isPlayer1 = game.player1_user_id === authStore.currentUser.id;
const opponent = isPlayer1 ? game.player2 : game.player1;
let outcome = 'loss';
if (game.is_draw) outcome = 'draw';
- else if (game.winner_user_id === authStore.currentUserID) outcome = 'win';
-
- const minutes = Math.floor(game.total_time / 60);
- const seconds = game.total_time % 60;
- const durationStr = `${minutes}m ${seconds}s`;
+ else if (game.winner_user_id === authStore.currentUser.id) outcome = 'win';
return {
id: game.id,
@@ -706,16 +717,14 @@ const fetchData = async () => {
outcome: outcome,
opponent: opponent?.nickname || 'Unknown Player',
amount: isPlayer1 ? game.player1_points : game.player2_points,
- duration: durationStr,
- created_at: game.began_at,
+ duration: `${Math.floor(game.total_time / 60)}m ${game.total_time % 60}s`,
+ began_at: game.began_at,
details: {
- marks: game.custom?.marks || 0,
- capotes: game.custom?.capotes || 0,
- bandeiras: game.custom?.bandeiras || 0
+ capotes: 0,
+ bandeiras: 0
}
};
});
-
games.value.push(...newData);
}
@@ -733,16 +742,23 @@ const setupObserver = () => {
const scrollContainer = document.querySelector('.custom-scrollbar');
- observer.value = new IntersectionObserver((entries) => {
- if (entries[0].isIntersecting && !isLoading.value) {
+ observer.value = new IntersectionObserver(async (entries) => {
+ const isGame = activeTab.value === 'game-history';
+ const hasMore = isGame ? pagination.value.games.hasMore : pagination.value.transactions.hasMore;
+
+ if (entries[0].isIntersecting && !isLoading.value && hasMore) {
fetchData();
}
- }, { root: scrollContainer, threshold: 0.1 });
+ }, {
+ root: scrollContainer,
+ threshold: 0.1,
+ rootMargin: '100px'
+ });
if (observerTarget.value) observer.value.observe(observerTarget.value);
};
-const resetAndFetch = () => {
+const resetAndFetch = async () => {
if (activeTab.value === 'transaction-history') {
transactions.value = [];
pagination.value.transactions = { page: 1, hasMore: true };
@@ -753,7 +769,44 @@ const resetAndFetch = () => {
pagination.value.games = { page: 1, hasMore: true };
}
- fetchData();
+ await nextTick();
+ await fetchData();
+ setupObserver();
+};
+
+const clearFilters = () => {
+ const isGameTab = activeTab.value === 'game-history';
+ const defaultSortColumn = isGameTab ? 'began_at' : 'transaction_datetime';
+
+ const isAlreadyDefault =
+ filters.value.startDate === '' &&
+ filters.value.endDate === '' &&
+ filters.value.sort.column === defaultSortColumn &&
+ filters.value.sort.order === 'desc' &&
+ (isGameTab
+ ? (filters.value.variant === 'all' && filters.value.outcome === 'all')
+ : (filters.value.type === 'all')
+ );
+
+ if (isAlreadyDefault) {
+ return;
+ }
+
+ if (isGameTab) {
+ filters.value.variant = 'all';
+ filters.value.outcome = 'all';
+ } else {
+ filters.value.type = 'all';
+ }
+
+ filters.value.startDate = '';
+ filters.value.endDate = '';
+ filters.value.sort = {
+ column: defaultSortColumn,
+ order: 'desc'
+ };
+
+ resetAndFetch();
};
const formatDate = (dateString) => {
@@ -895,13 +948,10 @@ const deleteAccount = async () => {
try {
await axios.delete(`${API_BASE_URL}/users/me`)
- // Logout user
await authStore.logout()
- // Close modal
showDeleteConfirmation.value = false
- // Redirect to home/login
router.push('/login')
} catch (err) {
deletingAccount.value = false
diff --git a/frontend/src/stores/api.js b/frontend/src/stores/api.js
index 619b762..4cdba6e 100644
--- a/frontend/src/stores/api.js
+++ b/frontend/src/stores/api.js
@@ -80,22 +80,35 @@ export const useAPIStore = defineStore('api', () => {
const queryParams = new URLSearchParams({
page: params.page || 1,
...(params.type && { type: params.type }),
+ ...(params.outcome && { outcome: params.outcome }),
...(params.status && { status: params.status }),
- sort_by: params.sort || 'began_at',
- sort_direction: params.direction || 'desc',
+ ...(params.date_from && { date_from: params.date_from }),
+ ...(params.date_to && { date_to: params.date_to }),
+ sort_by: params.sort_by || 'began_at',
+ sort_direction: params.sort_direction || 'desc',
}).toString()
- console.log(params, queryParams)
-
return axios.get(`${API_BASE_URL}/users/${authStore.currentUserID}/matches?${queryParams}`)
}
+ const getCurrentUserTransactions = (params = {}) => {
+ const queryParams = new URLSearchParams({
+ page: params.page || 1,
+ ...(params.type && { type: params.type }),
+ ...(params.date_from && { date_from: params.date_from }),
+ ...(params.date_to && { date_to: params.date_to }),
+ }).toString()
+
+ return axios.get(`${API_BASE_URL}/users/${authStore.currentUserID}/transactions?${queryParams}`)
+ }
+
return {
postLogin,
postLogout,
getAuthUser,
getGames,
getCurrentUserMatches,
+ getCurrentUserTransactions,
gameQueryParameters,
}
})