Skip to content

Commit 53a31a9

Browse files
committed
Merge branch 'pi-chat-redesign' of github.com:ibrahimmoazzam/rs into ibrahimmoazzam-pi-chat-redesign
2 parents f886500 + bc3f4c7 commit 53a31a9

File tree

7 files changed

+341
-65
lines changed

7 files changed

+341
-65
lines changed

bases/rsptx/interactives/runestone/mchoice/js/mchoice.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ export default class MultipleChoice extends RunestoneBase {
415415
studentVoteCount > 1) {
416416
this.renderMCMAFeedBack();
417417
} else {
418-
$(this.feedBackDiv).html("<p>Your Answer has been recorded</p>");
418+
$(this.feedBackDiv).html("<p>Your answer has been recorded</p>");
419419
$(this.feedBackDiv).attr("class", "alert alert-info");
420420
}
421421
}
@@ -570,7 +570,7 @@ export default class MultipleChoice extends RunestoneBase {
570570
studentVoteCount > 1) {
571571
this.renderMCMAFeedBack();
572572
} else {
573-
$(this.feedBackDiv).html("<p>Your Answer has been recorded</p>");
573+
$(this.feedBackDiv).html("<p>Your answer has been recorded</p>");
574574
$(this.feedBackDiv).attr("class", "alert alert-info");
575575
}
576576
}

bases/rsptx/web2py_server/applications/runestone/controllers/peer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ def peer_async():
711711
qnum = int(request.vars.question_num)
712712

713713
current_question, all_done = _get_numbered_question(assignment_id, qnum)
714+
assignment = db(db.assignments.id == assignment_id).select().first()
714715
course = db(db.courses.course_name == auth.user.course_name).select().first()
715716
course_attrs = getCourseAttributesDict(course.id, course.base_course)
716717
if "latex_macros" not in course_attrs:
@@ -721,6 +722,7 @@ def peer_async():
721722
course=get_course_row(db.courses.ALL),
722723
current_question=current_question,
723724
assignment_id=assignment_id,
725+
assignment_name = assignment.name,
724726
nextQnum=qnum + 1,
725727
all_done=all_done,
726728
**course_attrs,

bases/rsptx/web2py_server/applications/runestone/static/css/peer.css

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
#pi-instructor-interface .row, #pi-instructor-interface #imessage {
1+
/* +--------------------------------+ */
2+
/* | Peer Instruction (PI) Stylesheet | */
3+
/* +--------------------------------+ */
24

5+
/* ---------------------- */
6+
/* Instructor's interface */
7+
/* ---------------------- */
8+
#pi-instructor-interface .row, #pi-instructor-interface #imessage {
39
margin-right: 0px;
410
margin-left: 0px;
511
padding-left: 15px;
@@ -158,4 +164,172 @@
158164

159165
.autopermalink {
160166
display: none;
167+
}
168+
169+
/* ------------------- */
170+
/* Student's interface */
171+
/* ------------------- */
172+
#pi-student-interface .row, #pi-student-interface #imessage {
173+
margin-right: 0px;
174+
margin-left: 0px;
175+
padding-right: 15px;
176+
}
177+
178+
#discussion_panel {
179+
margin: 20px 0;
180+
background: #FBFBFB;
181+
border: 0.5px solid #C7CDD1;
182+
border-radius: 12px;
183+
box-shadow: 0px 20px 24px 0px rgba(17, 17, 17, 0.06);
184+
padding-left: 0px;
185+
padding-right: 0px;
186+
}
187+
188+
#discussion-panel-heading {
189+
font-size: 22px;
190+
font-weight: 500;
191+
padding: 12px 24px;
192+
background: #FBFBFB;
193+
border: 1px solid #C7CDD1;
194+
border-radius: 12px 12px 0px 0px;
195+
box-shadow: 0px 2px 2px 0px rgba(17, 17, 17, 0.06);
196+
}
197+
198+
#discussion-panel-heading p {
199+
margin: 0;
200+
}
201+
202+
#discussion-panel-peer-votes {
203+
border-bottom: 1px solid #C7CDD1;
204+
padding: 16px 24px;
205+
}
206+
207+
#discussion-panel-peer-votes-content {
208+
border-radius: 12px;
209+
border: 2px solid #C7CDD1;
210+
background: #FFFFFF;
211+
padding: 16px 32px;
212+
}
213+
214+
#discussion-panel-peer-votes-content p {
215+
margin: 0;
216+
line-height: 28px;
217+
}
218+
219+
#discussion-panel-peer-votes-content #peerlist {
220+
margin-bottom: 8px;
221+
}
222+
223+
#discussion-panel-messages {
224+
padding: 16px 24px;
225+
}
226+
227+
#discussion-panel-messages #messages {
228+
margin: 0;
229+
padding-left: 0;
230+
padding-right: 10px;
231+
min-height: 15vh;
232+
max-height: 35vh;
233+
overflow-y: auto;
234+
display: flex;
235+
flex-direction: column;
236+
}
237+
238+
#discussion-panel-messages #messages > li {
239+
margin-top: 8px;
240+
}
241+
242+
#discussion-panel-messages #messages .outgoing-mess + .incoming-mess,
243+
#discussion-panel-messages #messages .incoming-mess + .outgoing-mess {
244+
margin-top: 16px;
245+
}
246+
247+
#discussion-panel-messages #messages > li:first-child {
248+
margin-top: 0;
249+
}
250+
251+
#discussion-panel-messages #messages .outgoing-mess, #discussion-panel-messages #messages .incoming-mess {
252+
display: flex;
253+
flex-direction: column;
254+
font-style: normal;
255+
color: #333;
256+
gap: 4px;
257+
}
258+
259+
#discussion-panel-messages #messages .outgoing-mess {
260+
align-items: end;
261+
}
262+
263+
#discussion-panel-messages #messages .incoming-mess {
264+
align-items: start;
265+
}
266+
267+
#discussion-panel-messages #messages .sender {
268+
display: flex;
269+
font-size: 11px;
270+
gap: 8px;
271+
align-items: center;
272+
}
273+
274+
#discussion-panel-messages #messages .sender-initials {
275+
display: flex;
276+
background: #777777;
277+
height: 24px;
278+
width: 24px;
279+
border-radius: 50%;
280+
align-items: center;
281+
justify-content: center;
282+
color: #FFFFFF;
283+
}
284+
285+
#discussion-panel-messages #messages .sender-name {
286+
font-weight: 700;
287+
}
288+
289+
#discussion-panel-messages #messages .content {
290+
border-radius: 15px;
291+
padding: 8px 16px;
292+
}
293+
294+
#discussion-panel-messages #messages .outgoing-mess .sender-initials {
295+
order: 2;
296+
}
297+
298+
#discussion-panel-messages #messages .outgoing-mess .content {
299+
background: rgba(215, 241, 249, 0.60);
300+
}
301+
302+
#discussion-panel-messages #messages .incoming-mess .content {
303+
background: rgba(255, 255, 215, 0.60);
304+
}
305+
306+
#peer-message-box {
307+
display: flex;
308+
flex-direction: row;
309+
align-items: center;
310+
justify-content: space-between;
311+
width: 100%;
312+
border-radius: 12px;
313+
border: 2px solid #C7CDD1;
314+
background: #FFFFFF;
315+
padding: 8px 16px;
316+
margin-top: 10px;
317+
gap: 16px;
318+
}
319+
320+
#peer-message-box input {
321+
width: 100%;
322+
border: none;
323+
}
324+
325+
#sendpeermsg {
326+
background: none;
327+
margin: 0;
328+
padding: 0;
329+
display: flex;
330+
}
331+
332+
#sendpeermsg.disabled {
333+
pointer-events: none;
334+
opacity: 0.5;
161335
}

bases/rsptx/web2py_server/applications/runestone/static/js/peer.js

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Configuration for the PI steps and helper functions to handle step progression
1+
// Configuration for the PI steps and helper functions to handle step progression in the instructor's interface
22
const STEP_CONFIG = {
33
vote1: {
44
next: ['makep', 'facechat', 'makeabgroups'],
@@ -107,6 +107,42 @@ function handleButtonClick(event) {
107107
}
108108
}
109109

110+
// Function to render incoming and outgoing messages for the text chat
111+
function renderMessage({ from, text, direction }) {
112+
// Create message element
113+
const message = document.createElement("li");
114+
message.classList.add(`${direction}-mess`);
115+
116+
// Sender container
117+
const sender = document.createElement("div");
118+
sender.classList.add("sender");
119+
120+
// Thumbnail using sender initials
121+
const senderInitials = document.createElement("div");
122+
senderInitials.classList.add("sender-initials");
123+
let initials = from.split(" ").map(n => n.charAt(0)).join("").toUpperCase();
124+
senderInitials.textContent = initials;
125+
126+
// Sender name
127+
const senderName = document.createElement("div");
128+
senderName.classList.add("sender-name");
129+
senderName.textContent = direction === "outgoing" ? "You" : from;
130+
131+
sender.appendChild(senderInitials);
132+
sender.appendChild(senderName);
133+
134+
// Message content
135+
const content = document.createElement("div");
136+
content.classList.add("content");
137+
content.textContent = text;
138+
139+
// Append sender and content to message
140+
message.appendChild(sender);
141+
message.appendChild(content);
142+
143+
return message;
144+
}
145+
110146
var ws = null;
111147
var alertSet = false;
112148
function connect(event) {
@@ -119,15 +155,13 @@ function connect(event) {
119155
ws.onclose = function () {
120156
console.log("Websocket Closed")
121157
alert(
122-
"You have been disconnected from the peer instruction server. Will Reconnect."
158+
"You have been disconnected from the peer instruction server. Will reconnect."
123159
);
124160
connect();
125161
};
126162

127163
ws.onmessage = function (event) {
128-
var messages = document.getElementById("messages");
129-
var message = document.createElement("li");
130-
message.classList.add("incoming-mess");
164+
const messages = document.getElementById("messages");
131165
let mess = JSON.parse(event.data);
132166
// This is an easy to code solution for broadcasting that could go out to
133167
// multiple courses. It would be better to catch that on the server side
@@ -138,9 +172,15 @@ function connect(event) {
138172
}
139173
if (mess.type === "text") {
140174
if (!(mess.time in messageTrail)) {
141-
var content = document.createTextNode(`${mess.from}: ${mess.message}`);
142-
message.appendChild(content);
175+
let message = renderMessage({
176+
from: mess.from,
177+
text: mess.message,
178+
direction: "incoming"
179+
});
180+
181+
// Append message to messages container
143182
messages.appendChild(message);
183+
messages.scrollTop = messages.scrollHeight;
144184
messageTrail[mess.time] = mess.message;
145185
}
146186
} else if (mess.type === "control") {
@@ -275,7 +315,7 @@ function connect(event) {
275315
for (const key in adict) {
276316
let currAnswer = adict[key];
277317
let newpeer = document.createElement("p");
278-
newpeer.innerHTML = `${key} answered ${currAnswer}`;
318+
newpeer.innerHTML = `${key}: <strong>${currAnswer}</strong>`;
279319
peerlist.appendChild(newpeer);
280320
}
281321
break;
@@ -396,31 +436,43 @@ async function sendLtiScores(event) {
396436
// the server can then broadcast the message or send it to a
397437
// specific user
398438
async function sendMessage(event) {
399-
var input = document.getElementById("messageText");
400-
if (input.value.trim() === "") {
439+
const messages = document.getElementById("messages");
440+
const input = document.getElementById("messageText");
441+
const sendButton = document.getElementById("sendpeermsg");
442+
const messageText = input.value.trim();
443+
444+
if (messageText === "") {
401445
input.focus();
402446
return;
403447
}
448+
404449
let mess = {
405450
type: "text",
406451
from: `${user}`,
407-
message: input.value,
452+
message: messageText,
408453
time: Date.now(),
409454
broadcast: false,
410455
course_name: eBookConfig.course,
411456
div_id: currentQuestion,
412457
};
458+
413459
await publishMessage(mess);
414-
var messages = document.getElementById("messages");
415-
var message = document.createElement("li");
416-
message.classList.add("outgoing-mess");
417-
var content = document.createTextNode(`${user}: ${input.value}`);
418-
message.appendChild(content);
460+
461+
let message = renderMessage({
462+
from: user,
463+
text: messageText,
464+
direction: "outgoing"
465+
});
466+
467+
// Append message to messages container
419468
messages.appendChild(message);
469+
messages.scrollTop = messages.scrollHeight;
470+
420471
input.value = "";
421-
// focus tehe input box again
422472
input.focus();
423-
// not needed for onclick event.preventDefault()
473+
474+
// Disable the send button after sending a message
475+
sendButton.classList.add("disabled");
424476
}
425477

426478
function warnAndStopVote(event) {
@@ -731,11 +783,25 @@ async function setupPeerGroup() {
731783

732784
$(function () {
733785
let tinput = document.getElementById("messageText");
734-
if (tinput) {
735-
tinput.addEventListener("keyup", function (event) {
736-
if (event.keyCode === 13) {
786+
let sendButton = document.getElementById("sendpeermsg");
787+
788+
if (tinput && sendButton) {
789+
tinput.addEventListener("input", function () {
790+
let message = this.value.trim();
791+
if (message !== "") {
792+
sendButton.classList.remove("disabled");
793+
} else {
794+
sendButton.classList.add("disabled");
795+
}
796+
});
797+
798+
tinput.addEventListener("keydown", function (event) {
799+
if (event.key === "Enter") {
737800
event.preventDefault();
738-
document.getElementById("sendpeermsg").click();
801+
let message = this.value.trim();
802+
if (message != "") {
803+
document.getElementById("sendpeermsg").click();
804+
}
739805
}
740806
});
741807
}

0 commit comments

Comments
 (0)