Skip to content

Commit

Permalink
Requested Interview Features Update (Rave Radbury Edition) (tgstation…
Browse files Browse the repository at this point in the history
…#59621)

Added a few things that were requested by RaveRadbury to be added to the interview system:
* Where appropriate clickable links are now added to open a interview in similar fashion to tickets
* Changed fields to be read-only for admins looking at interviews while they're being written
* Added the ability to include markdown-style links to interview welcome messages and interview questions
* Updated the default questions to add a question about if the user has read the rules to demonstrate the ability to include links
  • Loading branch information
bobbah authored Jun 13, 2021
1 parent a6e31b6 commit 3147779
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 43 deletions.
10 changes: 8 additions & 2 deletions code/modules/interview/interview.dm
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
GLOB.interviews.approved_ckeys |= owner_ckey
GLOB.interviews.close_interview(src)
log_admin_private("[key_name(approved_by)] has approved interview #[id] for [owner_ckey][!owner ? "(DC)": ""].")
message_admins("<span class='adminnotice'>[key_name(approved_by)] has approved interview #[id] for [owner_ckey][!owner ? "(DC)": ""].</span>")
message_admins("<span class='adminnotice'>[key_name(approved_by)] has approved [link_self()] for [owner_ckey][!owner ? "(DC)": ""].</span>")
if (owner)
SEND_SOUND(owner, sound('sound/effects/adminhelp.ogg'))
to_chat(owner, "<font color='red' size='4'><b>-- Interview Update --</b></font>" \
Expand All @@ -79,7 +79,7 @@
GLOB.interviews.close_interview(src)
GLOB.interviews.cooldown_ckeys |= owner_ckey
log_admin_private("[key_name(denied_by)] has denied interview #[id] for [owner_ckey][!owner ? "(DC)": ""].")
message_admins("<span class='adminnotice'>[key_name(denied_by)] has denied interview #[id] for [owner_ckey][!owner ? "(DC)": ""].</span>")
message_admins("<span class='adminnotice'>[key_name(denied_by)] has denied [link_self()] for [owner_ckey][!owner ? "(DC)": ""].</span>")
addtimer(CALLBACK(GLOB.interviews, /datum/interview_manager.proc/release_from_cooldown, owner_ckey), 180)
if (owner)
SEND_SOUND(owner, sound('sound/effects/adminhelp.ogg'))
Expand Down Expand Up @@ -160,3 +160,9 @@
"response" = responses.len < i ? null : responses[i]
)
.["questions"] += list(data)

/**
* Generates a clickable link to open this interview
*/
/datum/interview/proc/link_self()
return "<a href='?_src_=holder;[HrefToken(TRUE)];interview=[REF(src)]'>Interview #[id]</a>"
2 changes: 1 addition & 1 deletion code/modules/interview/interview_manager.dm
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ GLOBAL_DATUM_INIT(interviews, /datum/interview_manager, new)
if(X.prefs.toggles & SOUND_ADMINHELP)
SEND_SOUND(X, sound('sound/effects/adminhelp.ogg'))
window_flash(X, ignorepref = TRUE)
to_chat(X, "<span class='adminhelp'>Interview for [ckey] enqueued for review. Current position in queue: [to_queue.pos_in_queue]</span>", confidential = TRUE)
to_chat(X, "<span class='adminhelp'>[to_queue.link_self()] for [ckey] enqueued for review. Current position in queue: [to_queue.pos_in_queue]</span>", confidential = TRUE)

/**
* Removes a ckey from the cooldown list, used for enforcing cooldown after an interview is denied.
Expand Down
5 changes: 4 additions & 1 deletion config/interviews.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Interview welcome message displayed at the top of all interview questionnaires
# Should help to describe why the questionnaire is being given to the interviewee
# You can include links using markdown-style link notation, like [our rules](https://tgstation13.org/wiki/Rules)
INTERVIEW_WELCOME_MSG Welcome to our server. As you have not played here before, or played very little, we'll need you to answer a few questions below. After you submit your answers they will be reviewed and you may be asked further questions before being allowed to play. Please be patient as there may be others ahead of you.

# Interview questions are listed here, in the order that they will be displayed in-game.
# You can include links using markdown-style link notation, like [our rules](https://tgstation13.org/wiki/Rules)
INTERVIEW_QUESTIONS Why have you joined the server today?
INTERVIEW_QUESTIONS Have you played space-station 13 before? If so, on what servers?
INTERVIEW_QUESTIONS Do you know anybody on the server today? If so, who?
INTERVIEW_QUESTIONS Do you have any additional comments?
INTERVIEW_QUESTIONS Have you read and understood our [rules](https://tgstation13.org/wiki/Rules)?
INTERVIEW_QUESTIONS Do you have any additional comments or questions?
119 changes: 80 additions & 39 deletions tgui/packages/tgui/interfaces/Interview.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Button, TextArea, Section, BlockQuote, NoticeBox } from '../components';
import {
Button,
TextArea,
Section,
BlockQuote,
NoticeBox,
} from '../components';
import { Window } from '../layouts';
import { useBackend } from '../backend';

Expand All @@ -14,76 +20,111 @@ export const Interview = (props, context) => {
connected,
} = data;

const rendered_status = status => {
const rendered_status = (status) => {
switch (status) {
case "interview_approved":
return (<NoticeBox success>This interview was approved.</NoticeBox>);
case "interview_denied":
return (<NoticeBox danger>This interview was denied.</NoticeBox>);
case 'interview_approved':
return <NoticeBox success>This interview was approved.</NoticeBox>;
case 'interview_denied':
return <NoticeBox danger>This interview was denied.</NoticeBox>;
default:
return (<NoticeBox info>
Your answers have been submitted. You are position {queue_pos} in
queue.</NoticeBox>);
return (
<NoticeBox info>
Your answers have been submitted. You are position {queue_pos} in
queue.
</NoticeBox>
);
}
};

// Matches a complete markdown-style link, capturing the whole [...](...)
const link_regex = /(\[[^[]+\]\([^)]+\))/;
// Decomposes a markdown-style link into the link and display text
const link_decompose_regex = /\[([^[]+)\]\(([^)]+)\)/;

// Renders any markdown-style links within a provided body of text
const linkify_text = (text) => {
let parts = text.split(link_regex);
for (let i = 1; i < parts.length; i += 2) {
const match = link_decompose_regex.exec(parts[i]);
parts[i] = (
<a key={'link' + i} href={match[2]}>
{match[1]}
</a>
);
}
return parts;
};

return (
<Window
width={500}
height={600}
canClose={is_admin}>
<Window width={500} height={600} canClose={is_admin}>
<Window.Content scrollable>
{(!read_only && (
<Section title="Welcome!">
<p>
{welcome_message}
</p>
</Section>)) || rendered_status(status)}
<p>{linkify_text(welcome_message)}</p>
</Section>
))
|| rendered_status(status)}
<Section
title="Questionnaire"
buttons={(
buttons={
<span>
<Button
content={read_only ? "Submitted" : "Submit"}
content={read_only ? 'Submitted' : 'Submit'}
onClick={() => act('submit')}
disabled={read_only} />
{!!is_admin && status === "interview_pending" && (
disabled={read_only}
/>
{!!is_admin && status === 'interview_pending' && (
<span>
<Button content="Admin PM"
enabled={connected} onClick={() => act('adminpm')} />
<Button content="Approve"
color="good" onClick={() => act('approve')} />
<Button content="Deny"
color="bad" onClick={() => act('deny')} />
<Button
content="Admin PM"
enabled={connected}
onClick={() => act('adminpm')}
/>
<Button
content="Approve"
color="good"
onClick={() => act('approve')}
/>
<Button
content="Deny"
color="bad"
onClick={() => act('deny')}
/>
</span>
)}
</span>
)}>
}>
{!read_only && (
<p>
Please answer the following questions,
and press submit when you are satisfied with your answers.
<br /><br />
Please answer the following questions, and press submit when you
are satisfied with your answers.
<br />
<br />
<b>You will not be able to edit your answers after submitting.</b>
</p>)}
</p>
)}
{questions.map(({ qidx, question, response }) => (
<Section key={qidx} title={`Question ${qidx}`}>
<p>{question}</p>
{(read_only && (
<BlockQuote>{response || "No response."}</BlockQuote>)) || (
<p>{linkify_text(question)}</p>
{((read_only || is_admin) && (
<BlockQuote>{response || 'No response.'}</BlockQuote>
)) || (
<TextArea
value={response}
fluid
height={10}
maxLength={500}
placeholder="Write your response here, max of 500 characters."
onChange={(e, input) => input !== response
onChange={(e, input) =>
input !== response
&& act('update_answer', {
qidx: qidx,
answer: input,
})} />)}
</Section>)
)}
})}
/>
)}
</Section>
))}
</Section>
</Window.Content>
</Window>
Expand Down

0 comments on commit 3147779

Please sign in to comment.