ronantakizawa/codereview-bench huggingface dataset:
Repository: chatwoot/chatwoot
File: app/services/contacts/filter_service.rb (Ruby)

Code before:
  ATTRIBUTE_MODEL = 'contact_attribute'.freeze

  def initialize(account, user, params)
    @account = account
    # TODO: Change the order of arguments in FilterService maybe?
    # account, user, params makes more sense
    super(params, user)
  end

  def perform
    @contacts = query_builder(@filters['contacts'])

    {
      contacts: @contacts,
      count: @contacts.count
    }
  end

  def filter_values(query_hash)
    current_val = query_hash['values'][0]
    if query_hash['attribute_key'] == 'phone_number'
      if current_val.present? && current_val.start_with?('+')
        current_val
      else
        "+#{current_val}"
      end
    elsif query_hash['attribute_key'] == 'country_code'
      current_val.downcase
    else
      current_val.is_a?(String) ? current_val.downcase : current_val
    end
  end

  # TODO: @account.contacts.resolved_contacts ? to stay consistant with the behavior in ui
  def base_relation
    @account.contacts
  end

  def filter_config
    {
      entity: 'Contact',
      table_name: 'contacts'
    }
  end

  private

  def equals_to_filter_string(filter_operator, current_index)
    return "= :value_#{current_index}" if filter_operator == 'equal_to'

    "!= :value_#{current_index}"

Review comment (suggestion):
```suggestion
      "+#{current_val&.delete('+')}"
```

Code after:
  ATTRIBUTE_MODEL = 'contact_attribute'.freeze

  def initialize(account, user, params)
    @account = account
    # TODO: Change the order of arguments in FilterService maybe?
    # account, user, params makes more sense
    super(params, user)
  end

  def perform
    validate_query_operator
    @contacts = query_builder(@filters['contacts'])

    {
      contacts: @contacts,
      count: @contacts.count
    }
  end

  def filter_values(query_hash)
    current_val = query_hash['values'][0]
    if query_hash['attribute_key'] == 'phone_number'
      "+#{current_val&.delete('+')}"
    elsif query_hash['attribute_key'] == 'country_code'
      current_val.downcase
    else
      current_val.is_a?(String) ? current_val.downcase : current_val
    end
  end

  # TODO: @account.contacts.resolved_contacts ? to stay consistant with the behavior in ui
  def base_relation
    @account.contacts
  end

  def filter_config
    {
      entity: 'Contact',
      table_name: 'contacts'
    }
  end

  private

  def equals_to_filter_string(filter_operator, current_index)
    return "= :value_#{current_index}" if filter_operator == 'equal_to'

    "!= :value_#{current_index}"
  end
end
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/routes/dashboard/settings/inbox/PreChatForm/PreChatFields.vue (Vue)

Code before:
    isFieldEditable(item) {
      return !item.enabled;
    },
    handlePreChatFieldOptions(event, type, item) {
      this.$emit('update', event, type, item);
    },
    onDragEnd() {
      this.$emit('dragEnd', this.preChatFieldOptions);
    },
  },
};
</script>

<template>
  <Draggable
    v-model="preChatFieldOptions"
    tag="tbody"
    item-key="name"
    @end="onDragEnd"
  >
    <template #item="{ element: item }">
      <tr class="border-b border-n-weak">
        <td class="pre-chat-field"><fluent-icon icon="drag" /></td>
        <td class="pre-chat-field">
          <ToggleSwitch
            v-model="item['enabled']"
            @change="handlePreChatFieldOptions($event, 'enabled', item)"
          />
        </td>
        <td
          class="pre-chat-field"
          :class="{ 'disabled-text': !item['enabled'] }"
        >
          {{ item.name }}
        </td>
        <td
          class="pre-chat-field"
          :class="{ 'disabled-text': !item['enabled'] }"
        >
          {{ item.type }}
        </td>
        <td class="pre-chat-field">
          <input
            v-model="item['required']"
            type="checkbox"
            :value="`${item.name}-required`"
            :disabled="!item['enabled']"
            @click="handlePreChatFieldOptions($event, 'required', item)"
          />
        </td>
        <td

Review comment (suggestion):
Instead of binding the v-model, let use `:model-value`

```suggestion
            :model-value="item['enabled']"
```

The `defineModel` inside the `Switch.vue` will automatically declare a prop with the same name and a corresponding update:propName event.

Code after:
    isFieldEditable(item) {
      return !item.enabled;
    },
    handlePreChatFieldOptions(event, type, item) {
      this.$emit('update', event, type, item);
    },
    onDragEnd() {
      this.$emit('dragEnd', this.preChatFieldOptions);
    },
  },
};
</script>

<template>
  <Draggable
    v-model="preChatFieldOptions"
    tag="tbody"
    item-key="name"
    @end="onDragEnd"
  >
    <template #item="{ element: item }">
      <tr class="border-b border-n-weak">
        <td class="pre-chat-field"><fluent-icon icon="drag" /></td>
        <td class="pre-chat-field">
          <ToggleSwitch
            :model-value="item['enabled']"
            @change="handlePreChatFieldOptions($event, 'enabled', item)"
          />
        </td>
        <td
          class="pre-chat-field"
          :class="{ 'disabled-text': !item['enabled'] }"
        >
          {{ item.name }}
        </td>
        <td
          class="pre-chat-field"
          :class="{ 'disabled-text': !item['enabled'] }"
        >
          {{ item.type }}
        </td>
        <td class="pre-chat-field">
          <input
            v-model="item['required']"
            type="checkbox"
            :value="`${item.name}-required`"
            :disabled="!item['enabled']"
            @click="handlePreChatFieldOptions($event, 'required', item)"
          />
        </td>
        <td
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue (Vue)

Code before:

const chatMetadata = computed(() => props.chat.meta || {});

const assignee = computed(() => chatMetadata.value.assignee || {});

const currentContact = computed(() => {
  return contactById.value(chatMetadata.value.sender.id);
});

const isActiveChat = computed(() => {
  return currentChat.value.id === props.chat.id;
});

const unreadCount = computed(() => props.chat.unread_count);

const hasUnread = computed(() => unreadCount.value > 0);

const isInboxNameVisible = computed(() => !activeInbox.value);

const lastMessageInChat = computed(() => getLastMessage(props.chat));

const inbox = computed(() => {
  const { inbox_id: inboxId } = props.chat;
  const stateInbox = inboxById.value(inboxId);
  return stateInbox;
});

const showInboxName = computed(() => {
  return (
    !props.hideInboxName &&
    isInboxNameVisible.value &&
    inboxesList.value.length > 1
  );
});

const showMetaSection = computed(() => {
  return (
    showInboxName.value ||
    (props.showAssignee && assignee.value.name) ||
    props.chat.priority
  );
});

const hasSlaPolicyId = computed(() => props.chat?.sla_policy_id);

const showLabelsSection = computed(() => {
  return props.chat.labels?.length > 0 || hasSlaPolicyId.value;
});

const messagePreviewClass = computed(() => {
  return [

Review comment (refactor):
Can we extract commonly accessed nested properties to reduce recalculation.
```suggestion
const inboxId = computed(() => props.chat.inbox_id);
  const inbox = computed(() => {
    return inboxId.value ? store.getters['inboxes/getInbox'](inboxId.value) : {};
});
```

Code after:
const chatMetadata = computed(() => props.chat.meta || {});

const assignee = computed(() => chatMetadata.value.assignee || {});

const senderId = computed(() => chatMetadata.value.sender?.id);

const currentContact = computed(() => {
  return senderId.value
    ? store.getters['contacts/getContact'](senderId.value)
    : {};
});

const isActiveChat = computed(() => {
  return currentChat.value.id === props.chat.id;
});

const unreadCount = computed(() => props.chat.unread_count);

const hasUnread = computed(() => unreadCount.value > 0);

const isInboxNameVisible = computed(() => !activeInbox.value);

const lastMessageInChat = computed(() => getLastMessage(props.chat));

const inboxId = computed(() => props.chat.inbox_id);

const inbox = computed(() => {
  return inboxId.value ? store.getters['inboxes/getInbox'](inboxId.value) : {};
});

const showInboxName = computed(() => {
  return (
    !props.hideInboxName &&
    isInboxNameVisible.value &&
    inboxesList.value.length > 1
  );
});

const showMetaSection = computed(() => {
  return (
    showInboxName.value ||
    (props.showAssignee && assignee.value.name) ||
    props.chat.priority
  );
});

const hasSlaPolicyId = computed(() => props.chat?.sla_policy_id);

const showLabelsSection = computed(() => {
  return props.chat.labels?.length > 0 || hasSlaPolicyId.value;
});
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue (Vue)

Code before:
  'deSelectConversation',
]);

const router = useRouter();

const hovered = ref(false);
const showContextMenu = ref(false);
const contextMenu = ref({
  x: null,
  y: null,
});

const currentChat = useMapGetter('getSelectedChat');
const inboxesList = useMapGetter('inboxes/getInboxes');
const activeInbox = useMapGetter('getSelectedInbox');
const accountId = useMapGetter('getCurrentAccountId');
const contactById = useMapGetter('contacts/getContact');
const inboxById = useMapGetter('inboxes/getInbox');

const chatMetadata = computed(() => props.chat.meta || {});

const assignee = computed(() => chatMetadata.value.assignee || {});

const currentContact = computed(() => {
  return contactById.value(chatMetadata.value.sender.id);
});

const isActiveChat = computed(() => {
  return currentChat.value.id === props.chat.id;
});

const unreadCount = computed(() => props.chat.unread_count);

const hasUnread = computed(() => unreadCount.value > 0);

const isInboxNameVisible = computed(() => !activeInbox.value);

const lastMessageInChat = computed(() => getLastMessage(props.chat));

const inbox = computed(() => {
  const { inbox_id: inboxId } = props.chat;
  const stateInbox = inboxById.value(inboxId);
  return stateInbox;
});

const showInboxName = computed(() => {
  return (
    !props.hideInboxName &&
    isInboxNameVisible.value &&
    inboxesList.value.length > 1
  );

Review comment (suggestion):
```suggestion
const chatMetadata = computed(() => props.chat.meta || {});
  const senderId = computed(() => chatMetadata.value.sender?.id);
  const currentContact = computed(() => {
    return senderId.value ? store.getters['contacts/getContact'](senderId.value) : {};
});
```

Code after:
  'deSelectConversation',
]);

const router = useRouter();
const store = useStore();

const hovered = ref(false);
const showContextMenu = ref(false);
const contextMenu = ref({
  x: null,
  y: null,
});

const currentChat = useMapGetter('getSelectedChat');
const inboxesList = useMapGetter('inboxes/getInboxes');
const activeInbox = useMapGetter('getSelectedInbox');
const accountId = useMapGetter('getCurrentAccountId');

const chatMetadata = computed(() => props.chat.meta || {});

const assignee = computed(() => chatMetadata.value.assignee || {});

const senderId = computed(() => chatMetadata.value.sender?.id);

const currentContact = computed(() => {
  return senderId.value
    ? store.getters['contacts/getContact'](senderId.value)
    : {};
});

const isActiveChat = computed(() => {
  return currentChat.value.id === props.chat.id;
});

const unreadCount = computed(() => props.chat.unread_count);

const hasUnread = computed(() => unreadCount.value > 0);

const isInboxNameVisible = computed(() => !activeInbox.value);

const lastMessageInChat = computed(() => getLastMessage(props.chat));

const inboxId = computed(() => props.chat.inbox_id);

const inbox = computed(() => {
  return inboxId.value ? store.getters['inboxes/getInbox'](inboxId.value) : {};
});

const showInboxName = computed(() => {
  return (
    !props.hideInboxName &&
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/components-next/captain/pageComponents/document/DocumentForm.vue (Vue)

Code before:

const isLoading = computed(() => formState.uiFlags.value.creatingItem);

const getErrorMessage = (field, errorKey) => {
  return v$.value[field].$error
    ? t(`CAPTAIN.DOCUMENTS.FORM.${errorKey}.ERROR`)
    : '';
};

const formErrors = computed(() => ({
  url: getErrorMessage('url', 'URL'),
  assistantId: getErrorMessage('assistantId', 'ASSISTANT'),
  pdfFile: getErrorMessage('pdfFile', 'PDF_FILE'),
}));

const handleCancel = () => emit('cancel');

const handleFileChange = event => {
  const file = event.target.files[0];
  if (file) {
    if (file.type !== 'application/pdf') {
      useAlert(t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.INVALID_TYPE'));
      event.target.value = '';
      return;
    }
    if (file.size > 10 * 1024 * 1024) {
      // 10MB
      useAlert(t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.TOO_LARGE'));
      event.target.value = '';
      return;
    }
    state.pdfFile = file;
    state.name = file.name.replace('.pdf', '');
  }
};

const openFileDialog = () => {
  // Use nextTick to ensure the ref is available
  nextTick(() => {
    if (fileInputRef.value) {
      fileInputRef.value.click();
    }
  });
};

const prepareDocumentDetails = () => {
  const formData = new FormData();
  formData.append('document[assistant_id]', state.assistantId);

  if (state.documentType === 'url') {
    formData.append('document[external_link]', state.url);

Review comment (suggestion):
Can we make it as as a constant instead of magic string.
```
 const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
```

Code after:

const documentTypeOptions = [
  { value: 'url', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.URL') },
  { value: 'pdf', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.PDF') },
];

const v$ = useVuelidate(validationRules, state);

const isLoading = computed(() => formState.uiFlags.value.creatingItem);

const hasPdfFileError = computed(() => v$.value.pdfFile.$error);

const getErrorMessage = (field, errorKey) => {
  return v$.value[field].$error
    ? t(`CAPTAIN.DOCUMENTS.FORM.${errorKey}.ERROR`)
    : '';
};

const formErrors = computed(() => ({
  url: getErrorMessage('url', 'URL'),
  assistantId: getErrorMessage('assistantId', 'ASSISTANT'),
  pdfFile: getErrorMessage('pdfFile', 'PDF_FILE'),
}));

const handleCancel = () => emit('cancel');

const handleFileChange = event => {
  const file = event.target.files[0];
  if (file) {
    if (file.type !== 'application/pdf') {
      useAlert(t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.INVALID_TYPE'));
      event.target.value = '';
      return;
    }
    if (file.size > MAX_FILE_SIZE) {
      // 10MB
      useAlert(t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.TOO_LARGE'));
      event.target.value = '';
      return;
    }
    state.pdfFile = file;
    state.name = file.name.replace(/\.pdf$/i, '');
  }
};

const openFileDialog = () => {
  // Use nextTick to ensure the ref is available
  nextTick(() => {
    if (fileInputRef.value) {
      fileInputRef.value.click();
    }
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/components-next/captain/pageComponents/assistant/EditAssistantForm.vue (Vue)

Code before:
            <label class="flex items-center gap-2">
              <input
                v-model="state.features.conversationFaqs"
                type="checkbox"
                class="form-checkbox"
              />
              {{
                t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_CONVERSATION_FAQS')
              }}
            </label>
            <label class="flex items-center gap-2">
              <input
                v-model="state.features.memories"
                type="checkbox"
                class="form-checkbox"
              />
              {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_MEMORIES') }}
            </label>
          </div>
        </div>

        <div class="flex justify-end">
          <Button
            size="small"
            :loading="isLoading"
            :label="t('CAPTAIN.ASSISTANTS.FORM.UPDATE')"
            @click="handleFeaturesUpdate"
          />
        </div>
      </div>
    </Accordion>
  </form>
</template>


Review comment (suggestion):
@scmmishra Do we need this class name?
```suggestion
```

Code after:
            {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.TITLE') }}
          </label>
          <div class="flex flex-col gap-2">
            <label class="flex items-center gap-2">
              <input
                v-model="state.features.conversationFaqs"
                type="checkbox"
                class="form-checkbox"
              />
              {{
                t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_CONVERSATION_FAQS')
              }}
            </label>
            <label class="flex items-center gap-2">
              <input
                v-model="state.features.memories"
                type="checkbox"
                class="form-checkbox"
              />
              {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_MEMORIES') }}
            </label>
            <label class="flex items-center gap-2">
              <input
                v-model="state.features.citations"
                type="checkbox"
                class="form-checkbox"
              />
              {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_CITATIONS') }}
            </label>
          </div>
        </div>

        <div class="flex justify-end">
          <Button
            size="small"
            :loading="isLoading"
            :label="t('CAPTAIN.ASSISTANTS.FORM.UPDATE')"
            @click="handleFeaturesUpdate"
          />
        </div>
      </div>
    </Accordion>
  </form>
</template>
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/components/widgets/conversation/ReplyBoxBanner.vue (Vue)

Code before:
      agentId,
    });
  },
});

const isUserTyping = computed(
  () => props.message !== '' && !props.isOnPrivateNote
);
const isUnassigned = computed(() => !assignedAgent.value);
const isAssignedToOtherAgent = computed(
  () => assignedAgent.value?.id !== currentUser.value?.id
);

const showSelfAssignBanner = computed(() => {
  return (
    isUserTyping.value && (isUnassigned.value || isAssignedToOtherAgent.value)
  );
});

const showBotHandoffBanner = computed(() => {
  return (
    props.message !== '' &&
    !props.isOnPrivateNote &&
    currentChat.value?.status === wootConstants.STATUS_TYPE.PENDING
  );
});

const botHandoffActionLabel = computed(() => {
  return assignedAgent.value?.id === currentUser.value?.id
    ? t('CONVERSATION.BOT_HANDOFF_REOPEN_ACTION')
    : t('CONVERSATION.BOT_HANDOFF_ACTION');
});

const selfAssignConversation = async () => {
  const { avatar_url, ...rest } = currentUser.value || {};
  assignedAgent.value = { ...rest, thumbnail: avatar_url };
};

const needsAssignmentToCurrentUser = computed(() => {
  return isUnassigned.value || isAssignedToOtherAgent.value;
});

const onClickSelfAssign = async () => {
  try {
    await selfAssignConversation();
    useAlert(t('CONVERSATION.CHANGE_AGENT'));
  } catch (error) {
    useAlert(t('CONVERSATION.CHANGE_AGENT_FAILED'));
  }
};


Review comment (suggestion):
```suggestion
const showBotHandoffBanner = computed(
  () =>
    isUserTyping.value &&
    currentChat.value?.status === wootConstants.STATUS_TYPE.PENDING
);

```

Code after:
      agentId,
    });
  },
});

const isUserTyping = computed(
  () => props.message !== '' && !props.isOnPrivateNote
);
const isUnassigned = computed(() => !assignedAgent.value);
const isAssignedToOtherAgent = computed(
  () => assignedAgent.value?.id !== currentUser.value?.id
);

const showSelfAssignBanner = computed(() => {
  return (
    isUserTyping.value && (isUnassigned.value || isAssignedToOtherAgent.value)
  );
});

const showBotHandoffBanner = computed(
  () =>
    isUserTyping.value &&
    currentChat.value?.status === wootConstants.STATUS_TYPE.PENDING
);

const botHandoffActionLabel = computed(() => {
  return assignedAgent.value?.id === currentUser.value?.id
    ? t('CONVERSATION.BOT_HANDOFF_REOPEN_ACTION')
    : t('CONVERSATION.BOT_HANDOFF_ACTION');
});

const selfAssignConversation = async () => {
  const { avatar_url, ...rest } = currentUser.value || {};
  assignedAgent.value = { ...rest, thumbnail: avatar_url };
};

const needsAssignmentToCurrentUser = computed(() => {
  return isUnassigned.value || isAssignedToOtherAgent.value;
});

const onClickSelfAssign = async () => {
  try {
    await selfAssignConversation();
    useAlert(t('CONVERSATION.CHANGE_AGENT'));
  } catch (error) {
    useAlert(t('CONVERSATION.CHANGE_AGENT_FAILED'));
  }
};

const reopenConversation = async () => {
  await store.dispatch('toggleStatus', {
Repository: chatwoot/chatwoot
File: app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue (Vue)

Code before:
<script setup>
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { I18nT } from 'vue-i18n';
import Twilio from './Twilio.vue';
import ThreeSixtyDialogWhatsapp from './360DialogWhatsapp.vue';
import CloudWhatsapp from './CloudWhatsapp.vue';
import WhatsappEmbeddedSignup from './WhatsappEmbeddedSignup.vue';
import ChannelSelector from 'dashboard/components/ChannelSelector.vue';

const route = useRoute();
const router = useRouter();
const { t } = useI18n();

const PROVIDER_TYPES = {
  WHATSAPP: 'whatsapp',
  TWILIO: 'twilio',
  WHATSAPP_CLOUD: 'whatsapp_cloud',
  WHATSAPP_EMBEDDED: 'whatsapp_embedded',
  WHATSAPP_MANUAL: 'whatsapp_manual',
  THREE_SIXTY_DIALOG: '360dialog',
};

const hasWhatsappAppId = computed(() => {
  return (
    window.chatwootConfig?.whatsappAppId &&
    window.chatwootConfig.whatsappAppId !== 'none'
  );

Review comment (suggestion):
```suggestion
import { useI18n, I18nT } from 'vue-i18n';
```

Code after:
<script setup>
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n, I18nT } from 'vue-i18n';
import Twilio from './Twilio.vue';
import ThreeSixtyDialogWhatsapp from './360DialogWhatsapp.vue';
import CloudWhatsapp from './CloudWhatsapp.vue';
import WhatsappEmbeddedSignup from './WhatsappEmbeddedSignup.vue';
import ChannelSelector from 'dashboard/components/ChannelSelector.vue';

const route = useRoute();
const router = useRouter();
const { t } = useI18n();

const PROVIDER_TYPES = {
  WHATSAPP: 'whatsapp',
  TWILIO: 'twilio',
  WHATSAPP_CLOUD: 'whatsapp_cloud',
  WHATSAPP_EMBEDDED: 'whatsapp_embedded',
  WHATSAPP_MANUAL: 'whatsapp_manual',
  THREE_SIXTY_DIALOG: '360dialog',
};

const hasWhatsappAppId = computed(() => {
  return (
    window.chatwootConfig?.whatsappAppId &&
    window.chatwootConfig.whatsappAppId !== 'none'
  );
});