reflect votes in dialogs #22

This commit is contained in:
Novattz
2026-03-28 15:06:09 +01:00
parent 85d670931a
commit 769213288e
2 changed files with 142 additions and 3 deletions

View File

@@ -0,0 +1,110 @@
import React, { useEffect, useState } from 'react'
import { invoke } from '@tauri-apps/api/core'
import {
Dialog,
DialogHeader,
DialogBody,
DialogFooter,
DialogActions,
} from '@/components/dialogs'
import { Button } from '@/components/buttons'
import { Icon, info } from '@/components/icons'
import VotesDisplay, { GameVotes } from '@/components/common/VotesDisplay'
export interface SmokeAPIVotesDialogProps {
visible: boolean
gameId: string | null
gameTitle: string | null
onConfirm: () => void
onClose: () => void
}
/**
* Shown before installing SmokeAPI on a Proton game.
* Fetches and displays community votes for SmokeAPI specifically,
* then lets the user confirm or cancel the installation.
*/
const SmokeAPIVotesDialog: React.FC<SmokeAPIVotesDialogProps> = ({
visible,
gameId,
gameTitle,
onConfirm,
onClose,
}) => {
const [votes, setVotes] = useState<GameVotes | null>(null)
const [loading, setLoading] = useState(false)
useEffect(() => {
if (!visible || !gameId) {
setVotes(null)
return
}
setLoading(true)
invoke<GameVotes[]>('get_game_votes', { gameId })
.then((results) => {
setVotes(results.find((v) => v.unlocker === 'smokeapi') ?? null)
})
.catch(() => setVotes(null))
.finally(() => setLoading(false))
}, [visible, gameId])
const hasVotes = votes && (votes.success > 0 || votes.fail > 0)
return (
<Dialog visible={visible} onClose={onClose} size="small">
<DialogHeader onClose={onClose} hideCloseButton={true}>
<h3>Install SmokeAPI</h3>
</DialogHeader>
<DialogBody>
<div className="smokeapi-votes-content">
<p className="smokeapi-votes-game">
<strong>{gameTitle}</strong>
</p>
<div className="smokeapi-votes-section">
<p className="smokeapi-votes-label">Community compatibility</p>
{loading ? (
<p className="smokeapi-votes-loading">Fetching votes...</p>
) : (
<VotesDisplay votes={votes} />
)}
</div>
{!loading && !hasVotes && (
<div className="smokeapi-votes-notice">
<Icon name={info} variant="solid" size="md" />
<span>
No one has rated this game yet. You'll be able to submit a rating after
installing.
</span>
</div>
)}
{!loading && hasVotes && (
<div className="smokeapi-votes-notice">
<Icon name={info} variant="solid" size="sm" />
<span>
These ratings are from other CreamLinux users. Results may vary.
</span>
</div>
)}
</div>
</DialogBody>
<DialogFooter>
<DialogActions>
<Button variant="secondary" onClick={onClose}>
Cancel
</Button>
<Button variant="primary" onClick={onConfirm}>
Install anyway
</Button>
</DialogActions>
</DialogFooter>
</Dialog>
)
}
export default SmokeAPIVotesDialog

View File

@@ -1,4 +1,5 @@
import React from 'react'
import React, { useEffect, useState } from 'react'
import { invoke } from '@tauri-apps/api/core'
import {
Dialog,
DialogHeader,
@@ -8,10 +9,12 @@ import {
} from '@/components/dialogs'
import { Button } from '@/components/buttons'
import { Icon, info } from '@/components/icons'
import VotesDisplay, { GameVotes } from '@/components/common/VotesDisplay'
export interface UnlockerSelectionDialogProps {
visible: boolean
gameTitle: string
gameId: string | null
gameTitle: string | null
onClose: () => void
onSelectCreamLinux: () => void
onSelectSmokeAPI: () => void
@@ -19,15 +22,39 @@ export interface UnlockerSelectionDialogProps {
/**
* Unlocker Selection Dialog component
* Allows users to choose between CreamLinux and SmokeAPI for native Linux games
* Allows users to choose between CreamLinux and SmokeAPI for native Linux games.
* Fetches and displays community vote data per unlocker.
*/
const UnlockerSelectionDialog: React.FC<UnlockerSelectionDialogProps> = ({
visible,
gameId,
gameTitle,
onClose,
onSelectCreamLinux,
onSelectSmokeAPI,
}) => {
const [creamVotes, setCreamVotes] = useState<GameVotes | null>(null)
const [smokeVotes, setSmokeVotes] = useState<GameVotes | null>(null)
useEffect(() => {
if (!visible || !gameId) {
setCreamVotes(null)
setSmokeVotes(null)
return
}
invoke<GameVotes[]>('get_game_votes', { gameId })
.then((results) => {
setCreamVotes(results.find((v) => v.unlocker === 'creamlinux') ?? null)
setSmokeVotes(results.find((v) => v.unlocker === 'smokeapi') ?? null)
})
.catch(() => {
// Votes are non-critical — silently fall back to "No votes yet"
setCreamVotes(null)
setSmokeVotes(null)
})
}, [visible, gameId])
return (
<Dialog visible={visible} onClose={onClose} size="medium">
<DialogHeader onClose={onClose} hideCloseButton={true}>
@@ -52,6 +79,7 @@ const UnlockerSelectionDialog: React.FC<UnlockerSelectionDialogProps> = ({
Native Linux DLC unlocker. Works best with most native Linux games and provides
better compatibility.
</p>
<VotesDisplay votes={creamVotes} />
<Button variant="primary" onClick={onSelectCreamLinux} fullWidth>
Install CreamLinux
</Button>
@@ -66,6 +94,7 @@ const UnlockerSelectionDialog: React.FC<UnlockerSelectionDialogProps> = ({
Cross-platform DLC unlocker. Try this if CreamLinux doesn't work for your game.
Automatically fetches DLC information.
</p>
<VotesDisplay votes={smokeVotes} />
<Button variant="secondary" onClick={onSelectSmokeAPI} fullWidth>
Install SmokeAPI
</Button>