This commit is contained in:
@@ -1209,7 +1209,7 @@ function ArtefactDetailPanel({ artefact, onClose, onUpdate, onDelete, projects =
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Submit for Review */}
|
{/* Submit for Review */}
|
||||||
{artefact.status === 'draft' && (
|
{['draft', 'revision_requested', 'rejected'].includes(artefact.status) && (
|
||||||
<div className="border-t border-border pt-6">
|
<div className="border-t border-border pt-6">
|
||||||
<button
|
<button
|
||||||
onClick={handleSubmitReview}
|
onClick={handleSubmitReview}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import { CheckCircle, XCircle, AlertCircle, FileText, Image as ImageIcon, Film, Sparkles, Globe } from 'lucide-react'
|
import { CheckCircle, XCircle, AlertCircle, FileText, Image as ImageIcon, Film, Sparkles, Globe, User } from 'lucide-react'
|
||||||
|
|
||||||
const STATUS_ICONS = {
|
const STATUS_ICONS = {
|
||||||
copy: FileText,
|
copy: FileText,
|
||||||
@@ -35,6 +35,10 @@ export default function PublicReview() {
|
|||||||
}
|
}
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
setArtefact(data)
|
setArtefact(data)
|
||||||
|
// Auto-set reviewer name if there's exactly one approver
|
||||||
|
if (data.approvers?.length === 1 && data.approvers[0].name) {
|
||||||
|
setReviewerName(data.approvers[0].name)
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError('Failed to load artefact')
|
setError('Failed to load artefact')
|
||||||
} finally {
|
} finally {
|
||||||
@@ -44,7 +48,7 @@ export default function PublicReview() {
|
|||||||
|
|
||||||
const handleAction = async (action) => {
|
const handleAction = async (action) => {
|
||||||
if (!reviewerName.trim()) {
|
if (!reviewerName.trim()) {
|
||||||
alert('Please enter your name')
|
alert('Please select or enter your name')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,15 +399,34 @@ export default function PublicReview() {
|
|||||||
<h3 className="text-lg font-semibold text-text-primary mb-4">Your Review</h3>
|
<h3 className="text-lg font-semibold text-text-primary mb-4">Your Review</h3>
|
||||||
|
|
||||||
<div className="space-y-4 mb-6">
|
<div className="space-y-4 mb-6">
|
||||||
|
{/* Reviewer identity */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-text-primary mb-1">Your Name *</label>
|
<label className="block text-sm font-medium text-text-primary mb-1">Reviewer</label>
|
||||||
<input
|
{artefact.approvers?.length === 1 ? (
|
||||||
type="text"
|
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary border border-border rounded-lg">
|
||||||
value={reviewerName}
|
<User className="w-4 h-4 text-text-tertiary" />
|
||||||
onChange={e => setReviewerName(e.target.value)}
|
<span className="text-sm text-text-primary">{artefact.approvers[0].name}</span>
|
||||||
placeholder="Enter your name"
|
</div>
|
||||||
className="w-full px-4 py-2 border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary bg-surface transition-colors"
|
) : artefact.approvers?.length > 1 ? (
|
||||||
/>
|
<select
|
||||||
|
value={reviewerName}
|
||||||
|
onChange={e => setReviewerName(e.target.value)}
|
||||||
|
className="w-full px-4 py-2 text-sm border border-border rounded-lg bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary transition-colors"
|
||||||
|
>
|
||||||
|
<option value="">Select your name...</option>
|
||||||
|
{artefact.approvers.map(a => (
|
||||||
|
<option key={a.id} value={a.name}>{a.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
) : (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={reviewerName}
|
||||||
|
onChange={e => setReviewerName(e.target.value)}
|
||||||
|
placeholder="Enter your name"
|
||||||
|
className="w-full px-4 py-2 text-sm border border-border rounded-lg bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary transition-colors"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -413,7 +436,7 @@ export default function PublicReview() {
|
|||||||
onChange={e => setFeedback(e.target.value)}
|
onChange={e => setFeedback(e.target.value)}
|
||||||
rows={4}
|
rows={4}
|
||||||
placeholder="Share your thoughts, suggestions, or required changes..."
|
placeholder="Share your thoughts, suggestions, or required changes..."
|
||||||
className="w-full px-4 py-2 border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary bg-surface transition-colors"
|
className="w-full px-4 py-2 text-sm border border-border rounded-lg bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary transition-colors"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3492,9 +3492,18 @@ app.get('/api/public/review/:token', async (req, res) => {
|
|||||||
limit: 1000,
|
limit: 1000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Resolve approver names
|
||||||
|
const approvers = [];
|
||||||
|
if (artefact.approver_ids) {
|
||||||
|
for (const id of artefact.approver_ids.split(',').filter(Boolean)) {
|
||||||
|
approvers.push({ id: Number(id), name: await getRecordName('Users', Number(id)) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
...artefact,
|
...artefact,
|
||||||
brand_name: await getRecordName('Brands', artefact.brand_id),
|
brand_name: await getRecordName('Brands', artefact.brand_id),
|
||||||
|
approvers,
|
||||||
version: versionData,
|
version: versionData,
|
||||||
version_number: reviewVersionNumber,
|
version_number: reviewVersionNumber,
|
||||||
texts,
|
texts,
|
||||||
@@ -3569,7 +3578,7 @@ app.post('/api/public/review/:token/reject', async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/public/review/:token/revision', async (req, res) => {
|
app.post('/api/public/review/:token/revision', async (req, res) => {
|
||||||
const { feedback } = req.body;
|
const { feedback, approved_by_name } = req.body;
|
||||||
try {
|
try {
|
||||||
const artefacts = await nocodb.list('Artefacts', {
|
const artefacts = await nocodb.list('Artefacts', {
|
||||||
where: `(approval_token,eq,${req.params.token})`,
|
where: `(approval_token,eq,${req.params.token})`,
|
||||||
@@ -3586,6 +3595,7 @@ app.post('/api/public/review/:token/revision', async (req, res) => {
|
|||||||
|
|
||||||
await nocodb.update('Artefacts', artefact.Id, {
|
await nocodb.update('Artefacts', artefact.Id, {
|
||||||
status: 'revision_requested',
|
status: 'revision_requested',
|
||||||
|
approved_by_name: approved_by_name || '',
|
||||||
feedback: feedback || '',
|
feedback: feedback || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user