[FIX] JE dois pouvoir modifier les nomes des parties d'un morceau
complexe #6
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,7 +5,5 @@ partitions/.svelte-kit/
|
||||
partitions/build/
|
||||
partitions/node_modules/
|
||||
partitions/static/pdf.worker.min.js
|
||||
partitions/.env
|
||||
api/vendor/
|
||||
api/composer.phar
|
||||
api/.env
|
||||
|
||||
@@ -343,6 +343,24 @@ if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'PUT')
|
||||
exit;
|
||||
}
|
||||
|
||||
// PUT /admin/scores/:id/pieces - Update pieces
|
||||
if (preg_match('#^admin/scores/(\d+)/pieces$#', $path, $matches) && $method === 'PUT') {
|
||||
$scoreId = $matches[1];
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$pieces = $input['pieces'] ?? [];
|
||||
|
||||
$result = $scanner->updatePieces($scoreId, $pieces);
|
||||
|
||||
if ($result['success']) {
|
||||
echo json_encode(['success' => true]);
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => $result['error']]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// DELETE /admin/scores/:id - Delete score
|
||||
if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'DELETE') {
|
||||
$scoreId = $matches[1];
|
||||
|
||||
@@ -489,6 +489,47 @@ class ScoreScanner {
|
||||
return ['success' => true];
|
||||
}
|
||||
|
||||
public function updatePieces(string $scoreId, array $pieces): array {
|
||||
$scoreDir = $this->scoresPath . $scoreId;
|
||||
$iniFile = $scoreDir . '/score.ini';
|
||||
|
||||
if (!file_exists($iniFile)) {
|
||||
return ['success' => false, 'error' => 'Score not found'];
|
||||
}
|
||||
|
||||
$ini = @parse_ini_file($iniFile, true);
|
||||
if ($ini === false) {
|
||||
return ['success' => false, 'error' => 'Failed to parse score.ini'];
|
||||
}
|
||||
|
||||
// Get existing info
|
||||
$name = $ini['info']['name'] ?? '';
|
||||
$compositor = $ini['info']['compositor'] ?? '';
|
||||
$ressource = $ini['info']['ressource'] ?? '';
|
||||
|
||||
// Rebuild ini content with new pieces
|
||||
$content = "[info]\n";
|
||||
$content .= "name = $name\n";
|
||||
$content .= "compositor = $compositor\n";
|
||||
if ($ressource) {
|
||||
$content .= "ressource = $ressource\n";
|
||||
}
|
||||
$content .= "\n[pieces]\n";
|
||||
$content .= "count = " . count($pieces) . "\n";
|
||||
|
||||
foreach ($pieces as $piece) {
|
||||
$num = $piece['number'] ?? $piece['id'];
|
||||
$pieceName = $piece['name'] ?? '';
|
||||
$content .= "$num = $pieceName\n";
|
||||
}
|
||||
|
||||
if (file_put_contents($iniFile, $content) === false) {
|
||||
return ['success' => false, 'error' => 'Failed to write score.ini'];
|
||||
}
|
||||
|
||||
return ['success' => true];
|
||||
}
|
||||
|
||||
public function deleteScore(string $scoreId): array {
|
||||
$scoreDir = $this->scoresPath . $scoreId;
|
||||
|
||||
|
||||
@@ -136,6 +136,15 @@ export const apiService = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async updatePieces(id: string, pieces: { id: string; name: string }[]): Promise<{ success: boolean; error?: string }> {
|
||||
const formattedPieces = pieces.map((p, i) => ({
|
||||
number: i + 1,
|
||||
name: p.name || `Partie ${i + 1}`
|
||||
}));
|
||||
const response = await api.put(`/admin/scores/${id}/pieces`, { pieces: formattedPieces });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async deleteScore(id: string): Promise<{ success: boolean; error?: string }> {
|
||||
const response = await api.delete(`/admin/scores/${id}`);
|
||||
return response.data;
|
||||
|
||||
@@ -61,6 +61,29 @@
|
||||
let uploadWatermark = $state(false);
|
||||
let uploadWatermarkPosition = $state<'left' | 'right'>('left');
|
||||
|
||||
// Edit pieces
|
||||
let editingPieces = $state(false);
|
||||
let piecesEdit = $state<{id: string; name: string}[]>([]);
|
||||
let savingPieces = $state(false);
|
||||
|
||||
async function savePieces() {
|
||||
savingPieces = true;
|
||||
try {
|
||||
const result = await apiService.updatePieces(scoreId, piecesEdit);
|
||||
if (result.success) {
|
||||
selectedScorePieces = [...piecesEdit];
|
||||
editingPieces = false;
|
||||
} else {
|
||||
alert('Erreur: ' + result.error);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert('Erreur lors de la sauvegarde');
|
||||
} finally {
|
||||
savingPieces = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-set default key when instrument changes
|
||||
$effect(() => {
|
||||
if (uploadInstrument) {
|
||||
@@ -375,6 +398,53 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Parties -->
|
||||
<div class="bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden mb-6">
|
||||
<div class="px-6 py-4 border-b border-gray-200 bg-gray-50 flex items-center justify-between">
|
||||
<h2 class="text-lg font-semibold text-ohmj-primary">Parties ({selectedScorePieceCount})</h2>
|
||||
{#if !editingPieces}
|
||||
<button onclick={() => { piecesEdit = [...selectedScorePieces]; editingPieces = true; }} class="text-ohmj-primary hover:text-ohmj-secondary text-sm font-medium">
|
||||
Modifier
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="p-4">
|
||||
{#if editingPieces}
|
||||
<div class="space-y-3">
|
||||
{#each piecesEdit as piece, i}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-500 w-8">#{i + 1}</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={piece.name}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded-md text-sm"
|
||||
placeholder="Nom de la partie"
|
||||
/>
|
||||
<button onclick={() => piecesEdit = piecesEdit.filter((_, idx) => idx !== i)} class="text-red-500 hover:text-red-700 p-2" title="Supprimer">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
<button onclick={() => piecesEdit = [...piecesEdit, {id: String(piecesEdit.length + 1), name: ''}]} class="text-ohmj-primary hover:text-ohmj-secondary text-sm font-medium">
|
||||
+ Ajouter une partie
|
||||
</button>
|
||||
<div class="flex gap-2 pt-3 border-t">
|
||||
<button onclick={() => { piecesEdit = [...selectedScorePieces]; editingPieces = false; }} class="px-4 py-2 text-gray-600 hover:text-gray-800 text-sm">Annuler</button>
|
||||
<button onclick={savePieces} disabled={savingPieces} class="px-4 py-2 bg-ohmj-primary text-white rounded hover:bg-ohmj-secondary text-sm disabled:opacity-50">
|
||||
{savingPieces ? 'Enregistrement...' : 'Enregistrer'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{#each selectedScorePieces as piece}
|
||||
<span class="px-3 py-1 bg-gray-100 rounded-full text-sm">{piece.name || `Partie ${piece.id}`}</span>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
|
||||
Reference in New Issue
Block a user