diff --git a/app/javascript/retrospring/features/answerbox/smile.ts b/app/javascript/retrospring/features/answerbox/smile.ts
new file mode 100644
index 00000000..5abfaa49
--- /dev/null
+++ b/app/javascript/retrospring/features/answerbox/smile.ts
@@ -0,0 +1,60 @@
+import Rails from '@rails/ujs';
+
+import I18n from '../../../legacy/i18n';
+import { showNotification, showErrorNotification } from 'utilities/notifications';
+
+export function answerboxSmileHandler(event: Event): void {
+ const button = event.target as HTMLButtonElement;
+ const id = button.dataset.aId;
+ const action = button.dataset.action;
+ let count = Number(document.querySelector(`#ab-smile-count-${id}`).innerHTML);
+ let success = false;
+ let targetUrl;
+
+ if (action === 'smile') {
+ count++;
+ targetUrl = '/ajax/create_smile';
+ }
+ else if (action === 'unsmile') {
+ count--;
+ targetUrl = '/ajax/destroy_smile';
+ }
+
+ button.disabled = true;
+
+ Rails.ajax({
+ url: targetUrl,
+ type: 'POST',
+ data: new URLSearchParams({
+ id: id
+ }).toString(),
+ success: (data) => {
+ success = data.success;
+ if (success) {
+ document.querySelector(`#ab-smile-count-${id}`).innerHTML = String(count);
+ }
+
+ showNotification(data.message, data.success);
+ },
+ error: (data, status, xhr) => {
+ console.log(data, status, xhr);
+ showErrorNotification(I18n.translate('frontend.error.message'));
+ },
+ complete: () => {
+ button.disabled = false;
+
+ if (success) {
+ switch(action) {
+ case 'smile':
+ button.dataset.action = 'unsmile';
+ button.innerHTML = ` ${count}`;
+ break;
+ case 'unsmile':
+ button.dataset.action = 'smile';
+ button.innerHTML = ` ${count}`;
+ break;
+ }
+ }
+ }
+ });
+}
\ No newline at end of file